Intro

Template based on Rmarkdown, using the united HTML theme.

Refer to a sub section. Citing an article (Adams 1993). Refer to section [Analysis].

Input

Loading libraries:

library(DT)
library(ggplot2)
library(xfun)
library(SignalingProfiler)
library(tidyverse)
library(igraph)
source('./0.libraries.R')

Run SignalingProfiler 2.0 in both conditions

analyses <- c('ima_ctrl', 'res_sens')
cell_lines <- c('LAMA84', 'K562')

solver = 'cplex'
carnival_options = default_CARNIVAL_options(solver)

# =============================================================== #
# Protein activity inference
# =============================================================== #

for(analysis in analyses){

  for(cell_line in cell_lines){

    phospho_df <- read_tsv(paste0('../input/phospho_', cell_line, '_',
                                  #if K562 sens_res and ima_ctrl, if LAMA just ima_ctrl
                                  ifelse(cell_line == 'K562', analysis, 'ima_ctrl'),
                                  '_SP.tsv'))

    prot_df <- read_tsv(paste0('../input/prot_', cell_line, '_',
                               #if K562 sens_res and ima_ctrl, if LAMA just ima_ctrl
                               ifelse(cell_line == 'K562', analysis, 'ima_ctrl'),
                               '_SP.tsv'))

    # Kinase Activity Inference
    kin_phos_activity_foot <- run_footprint_based_analysis(omic_data = phospho_df,
                                                           analysis = 'ksea',
                                                           organism = 'human',
                                                           reg_minsize = 3,
                                                           exp_sign = FALSE,
                                                           integrated_regulons = TRUE,
                                                           hypergeom_corr = TRUE,
                                                           GO_annotation = TRUE,
                                                           correct_proteomics = TRUE,
                                                           prot_df = prot_df)

    # Infer activity from regulatory phosphosites
    phosphoscore_df <- phosphoscore_computation(phosphoproteomic_data = phospho_df,
                                                organism = 'human',
                                                activatory = TRUE ,
                                                GO_annotation = TRUE)

    # Combine footprint- and PhosphoScore
    combined_kin_phos <- combine_footprint_and_phosphoscore(footprint_output = kin_phos_activity_foot,
                                                            phosphoscore_df =  phosphoscore_df,
                                                            analysis =  'ksea')

    toy_kin <- combined_kin_phos
    toy_other <- phosphoscore_df %>%
      dplyr::filter(!mf %in% c('kin', 'phos', 'tf')) %>%
      dplyr::rename(final_score = phosphoscore) %>%
      dplyr::mutate(method = 'PhosphoScore')

    toy_tf <- phosphoscore_df %>%
      dplyr::filter(mf == 'tf')
    toy_tf$final_score <- toy_tf$phosphoscore
    toy_tf$method = 'PhosphoScore'

    # create a unified 'activity modulation' table for the next steps
    prot_activity_df <- dplyr::bind_rows(toy_kin, toy_other, toy_tf) %>%
      dplyr::select(UNIPROT, gene_name, mf, final_score, method)

    ## ProteoScore
    proteo_score_df <-
      SignalingProfiler::activity_from_proteomics(prot_df = prot_df,
                                                  organism = "human")

    ## Combine ProteoScore and Activities

    activity_proteo_combined_filtered <-
      SignalingProfiler::combine_activityscore_proteoscore(activity_score = prot_activity_df,
                                                           proteo_score = proteo_score_df)
    activity_proteo_combined_filtered$final_score <-
      as.numeric(activity_proteo_combined_filtered$final_score)

    prot_activity_total_df <- activity_proteo_combined_filtered

    if(cell_line == 'K562'){
      k562_df <- prot_activity_total_df
    }else{
      lama84_df <- prot_activity_total_df
    }
  }

  if(analysis == 'ima_ctrl'){

    full_join(k562_df, lama84_df, by = c('gene_name', 'mf'), suffix = c('.K562', '.LAMA84')) -> merged_table

    # ggplot(merged_table, aes(x = final_score.K562, y = final_score.LAMA84)) +
    #   geom_point() +
    #   geom_hline(yintercept = 0) +
    #   geom_vline(xintercept = 0)

    merged_table <- merged_table %>% mutate(conc = final_score.K562 * final_score.LAMA84)

    write_tsv(merged_table, paste0('../results/', analysis, '/final_score.tsv'))

  } else {

    write_tsv(prot_activity_total_df, paste0('../results/', analysis, '/final_score.tsv'))

  }

}

# =============================================================== #
# Network creation and optimization
# =============================================================== #

for(analysis in analyses){
  if(analysis == 'ima_ctrl'){
    prot_df_lama <-  read_tsv(paste0('../input/prot_LAMA84_ima_ctrl_SP.tsv'))
    phospho_df_lama <- read_tsv(paste0('../input/phospho_LAMA84_ima_ctrl_SP.tsv'))
    prot_df_k562 <-  read_tsv(paste0('../input/prot_K562_ima_ctrl_SP.tsv'))
    phospho_df_k562 <- read_tsv(paste0('../input/phospho_K562_ima_ctrl_SP.tsv'))

    bind_rows(prot_df_lama, prot_df_k562) %>% distinct(gene_name) -> prot_df
    bind_rows(phospho_df_lama, phospho_df_k562) %>% distinct(gene_name) -> phospho_df

    # Read merged activity
    merged_table <- read_tsv(paste0('../results/', analysis, '/final_score.tsv'))
    activity_df <- merged_table %>% filter(conc > 0) # take only consistent proteins

    activity_df %>%
      filter(method.K562 != 'proteoscore' | method.LAMA84 != 'proteoscore') -> both_not_proteo

    activity_df %>%
      filter((method.K562 == 'proteoscore' | method.LAMA84 == 'proteoscore') & mf == 'tf') -> proteo_tf

    bind_rows(proteo_tf, both_not_proteo) -> activity_df_tot
  }else{
    phospho_df <- read_tsv(paste0('../input/phospho_K562_', analysis, '_SP.tsv'))
    prot_df <- read_tsv(paste0('../input/prot_K562_', analysis, '_SP.tsv'))

    activity_df_tot <- read_tsv(paste0(paste0('../results/', analysis, '/final_score.tsv')))
  }

  # ========================================================================== #
  # Build naive network
  # ========================================================================== #

   # # PKN preprocessing
    PKN_table <- choose_PKN(organism = 'human',
                            with_atlas = FALSE,
                            direct = TRUE,
                            custom = FALSE,
                            custom_path = NULL)

    # Preprocess according to the different condition
    PKN_expressed <- preprocess_PKN(omics_data = list(prot_df, phospho_df),
                                    PKN_table = PKN_table)

    # In the two-layered network separate KIN/PHOS/OTHERs and TFs
    kin_phos_other <- activity_df_tot %>%
      dplyr::filter(mf %in% c('kin', 'phos', 'other'))

    tfs <- activity_df_tot %>%
      dplyr::filter(mf == 'tf')

    naive_network <- two_layer_naive_network(starts_gn = c('BCR_ABL'),
                                             intermediate_gn = kin_phos_other$gene_name,
                                             targets_gn = tfs$gene_name,
                                             PKN_table = PKN_expressed, #or PKN_human
                                             max_length_1 = 3,
                                             max_length_2 = 4,
                                             connect_all = TRUE,
                                             rds_path = paste0('../results/', analysis, '/naive_network.rds'),
                                             sif_path = paste0('../results/', analysis, '/naive_network.sif'))

  # ===================== #
  # CARNIVAL optimization
  # ===================== #
  naive_network <- readRDS(paste0('../results/', analysis, '/naive_network.rds'))
  # Set receptor list
  receptor_list <- list('BCR_ABL' = -1)

  if(analysis == 'ima_ctrl'){

    # Get and parse protein activity
    activity_df_for_carnival <- activity_df_tot %>% mutate(method = paste0(method.K562, ';', method.LAMA84)) %>%
      rowwise() %>%
      mutate(final_score = mean(c_across(c(final_score.K562, final_score.K562)), na.rm = TRUE)) %>%
      ungroup() %>%
      dplyr::select(UNIPROT = UNIPROT.K562, gene_name, mf, method, final_score)

    # Get and parse Phosphoproteomics
    prot_df_lama <-  read_tsv(paste0('../input/prot_LAMA84_ima_ctrl_SP.tsv'))
    phospho_df_lama <- read_tsv(paste0('../input/phospho_LAMA84_ima_ctrl_SP.tsv'))
    prot_df_k562 <-  read_tsv(paste0('../input/prot_K562_ima_ctrl_SP.tsv'))
    phospho_df_k562 <- read_tsv(paste0('../input/phospho_K562_ima_ctrl_SP.tsv'))

    inner_join(phospho_df_k562, phospho_df_lama, by = c('gene_name', 'UNIPROT', 'aminoacid', 'position', 'significant'),
               suffix = c('.K562', '.LAMA84')) -> joined_omics

    agreed_phospho_df <- joined_omics %>% mutate(conc = difference.K562*difference.LAMA84) %>% filter(conc > 0)

    agreed_phospho_df_final <- agreed_phospho_df %>%
      rowwise() %>%
      mutate(final_score = mean(c_across(c(difference.K562, difference.LAMA84)), na.rm = TRUE)) %>%
      ungroup() %>%
      dplyr::select(UNIPROT, gene_name, aminoacid, position, difference = final_score,
                    sequence_window = sequence_window.LAMA84, significant, logpval = logpval.K562)

    phospho_df <- agreed_phospho_df_final
    bind_rows(prot_df_lama, prot_df_k562) %>% distinct(gene_name) -> prot_df_whole
    bind_rows(phospho_df_lama, phospho_df_k562) %>% distinct(gene_name) -> phospho_df_whole

  }else{

    activity_df_for_carnival <- activity_df_tot

    # Get Phosphoproteomics
    phospho_df <- read_tsv(paste0('../input/phospho_K562_', analysis, '_SP.tsv'))
  }


  carnival_input_table <- prepare_carnival_input(naive_network,
                                                 activity_df_for_carnival,
                                                 receptor_list,
                                                 organism = 'human')

  # # FIRST RUN: RECEPTOR to KIN, PHOS, OTHERS
  receptors_df <- carnival_input_table %>% dplyr::filter(mf == 'rec')

  target1_df <- carnival_input_table %>%
    dplyr::filter(mf %in% c('kin', 'phos', 'other'))

  naive_network_df <- readr::read_tsv(paste0('../results/', analysis, '/naive_network.sif'),
                                      col_names = c('source', 'interaction', 'target'))
  
  output1 <- run_carnival_and_create_graph(source_df = receptors_df,
                                             target_df = target1_df,
                                             naive_network = unique(naive_network_df),
                                             proteins_df = carnival_input_table,
                                             organism = 'human',
                                             carnival_options = carnival_options,
                                             files = FALSE,
                                             direct = TRUE,
                                             with_atlas = FALSE)

  # SECOND RUN: from KIN, PHOS, OTHERS to TFs
  run1_output_nodes <- convert_output_nodes_in_next_input(output1)
  run1_output_nodes$UNIPROT <- ''

  source_df <- run1_output_nodes %>%
    dplyr::filter(mf %in% c('kin', 'phos', 'other'))

  target2_df <- carnival_input_table %>%
    dplyr::filter(mf == 'tf')

  output2 <- run_carnival_and_create_graph(source_df = source_df,
                                           target_df = target2_df,
                                           naive_network = unique(naive_network_df),
                                           proteins_df = carnival_input_table,
                                           organism = 'human',
                                           carnival_options = carnival_options,
                                           direct = TRUE,
                                           with_atlas = FALSE,
                                           files = FALSE)

  # UNION OF RUN1 and RUN2 graphs
  union <- union_of_graphs(graph_1 = output1$igraph_network,
                           graph_2 = output2$igraph_network,
                           proteins_df = carnival_input_table,
                           files = TRUE,
                           path_sif = paste0('../results/', analysis, '/merged.sif'),
                           path_rds = paste0('../results/', analysis, '/merged.rds'))

  sp_output_df <- expand_and_map_edges(optimized_object = sp_output,
                                       organism = 'human',
                                       phospho_df = phospho_df,
                                       files = TRUE,
                                       direct = TRUE,
                                       with_atlas = FALSE,
                                       path_sif = paste0('../results/', analysis, '/validated.sif'),
                                       path_rds = paste0('../results/', analysis, '/validated.rds')
                                       )
}

# =============================================================== #
# PhenoScore computation
# =============================================================== #

# Ima vs Ctrl
prot_df_lama <-  read_tsv(paste0('../input/prot_LAMA84_ima_ctrl_SP.tsv'))
phospho_df_lama <- read_tsv(paste0('../input/phospho_LAMA84_ima_ctrl_SP.tsv'))
prot_df_k562 <-  read_tsv(paste0('../input/prot_K562_ima_ctrl_SP.tsv'))
phospho_df_k562 <- read_tsv(paste0('../input/phospho_K562_ima_ctrl_SP.tsv'))

inner_join(phospho_df_k562, phospho_df_lama, by = c('gene_name', 'UNIPROT', 'aminoacid', 'position', 'significant'),
           suffix = c('.K562', '.LAMA84')) -> joined_omics

agreed_phospho_df <- joined_omics %>% mutate(conc = difference.K562*difference.LAMA84) %>% filter(conc > 0)

agreed_phospho_df_final <- agreed_phospho_df %>%
  rowwise() %>%
  mutate(final_score = mean(c_across(c(difference.K562, difference.LAMA84)), na.rm = TRUE)) %>%
  ungroup() %>%
  dplyr::select(UNIPROT, gene_name, aminoacid, position, difference = final_score,
                sequence_window = sequence_window.LAMA84, significant, logpval = logpval.K562)

bind_rows(prot_df_lama, prot_df_k562) %>% distinct(gene_name) -> prot_df_whole
bind_rows(phospho_df_lama, phospho_df_k562) %>% distinct(gene_name) -> phospho_df_whole

# Select also the desired phenotypes
desired_phenotypes <- read_tsv('../input/phenotypes_df_new.tsv') %>% filter(selection == 'x')
pheno_table_distances <- phenoscore_network_preprocessing(proteomics = prot_df_whole,
                                                          phospho = phospho_df_whole)

analyses <- c('ima_ctrl', 'res_sens')

for(analysis in analyses){

  if(analysis == 'ima_ctrl'){
    phospho_df <- agreed_phospho_df_final

  }else{
    phospho_df <- read_tsv('../input/phospho_K562_res_sens_SP.tsv')
  }
  
   input_path <- paste0('../results/', analysis)

    sp_output <- read_rds(paste0(input_path, '/validated.rds'))

    sp_output$igraph_network <- graph_from_data_frame(d = sp_output$edges_df, vertices = sp_output$nodes_df)

    #sp_graph <- graph_from_data_frame(d = sp_output$edges_df %>% mutate_at('sign', as.character), vertices = sp_output$nodes_df)

    # sp_output$nodes_df <- sp_output$nodes_df %>% mutate(final_score = ifelse(discordant == TRUE, NA, final_score))
    sp_output$edges_df %>% mutate_at('sign', as.character) -> sp_output$edges_df

    toy_phenoscore_output<- phenoscore_computation(proteins_df = sp_output$nodes_df,
                                                   desired_phenotypes = c(desired_phenotypes$phenotypes,'AUTOPHAGY'),
                                                   pheno_distances_table = pheno_table_distances,
                                                   sp_graph = sp_output$igraph_network,
                                                   # closeness of proteins to phenotypes
                                                   path_length = 4,
                                                   stat = 'mean',
                                                   zscore_threshold = -1.96,
                                                   # exclude random phenotypes
                                                   n_random = 1000,
                                                   pvalue_threshold = 0.05,
                                                   # optimized network  specificity
                                                   remove_cascade = TRUE,
                                                   node_idx = FALSE,
                                                   use_carnival_activity = TRUE)

    write_rds(toy_phenoscore_output, paste0(input_path, '/phenoscore.rds'))

    solver = 'cplex'
    carnival_options <- default_CARNIVAL_options(solver)

    opt1 <- optimize_pheno_network(sp_object = toy_phenoscore_output,
                                   organism = 'human',
                                   phospho_df = phospho_df,
                                   carnival_options = carnival_options,
                                   files = TRUE,
                                   direct = TRUE,
                                   with_atlas = FALSE,
                                   path_sif = paste0(input_path, '/pheno_opt1.sif'),
                                   path_rds = paste0(input_path, '/pheno_opt1.rds'))

    optimized_sp_output <- readRDS(paste0(input_path, '/pheno_opt1.rds'))

    #
    # # VISUALIZATION OF THE MODEL
    #
    final_sp_visualization <- format_for_visualization(optimized_sp_output)

    RCy3::createNetworkFromIgraph(igraph=final_sp_visualization$igraph_network,
                                  title = paste0(analysis),
                                  collection = 'To_phenotypes')
    # Set in Cytoscape the SignalingProfiler style available in SignalingProfiler R package
  #  data_path <- system.file("extdata", "SP_pheno_layout.xml", package = "SignalingProfiler")
  #  RCy3::importVisualStyles(filename = data_path)
    RCy3::setVisualStyle('SP_pheno_layout')
}

Sensitive cells Imatinib characterization

Inferred proteins characterization

We first keep only proteins that have the same modulation in K562 and LAMA84 cell line. We use the proteoscore for transcription factors.

Scatterplot of inferred proteins

activity_df <- read_tsv('../results/ima_ctrl/final_score.tsv', show_col_types = FALSE)
activity_df %>% filter(mf == 'other') -> top_table
activity_df %>% filter(mf != 'other') -> bottom_table
plot_trick <- bind_rows(top_table,bottom_table)

color_list <- list(kin = '#D4145A', phos = '#009245', other = '#BA9BC9', tf = '#F7931E')

ggplot(plot_trick, aes(x = final_score.K562, y = final_score.LAMA84, label = gene_name)) +
  geom_point(aes(color = mf)) +
  geom_hline(yintercept = 0) +
  geom_vline(xintercept = 0) +
  xlab('Activity modulation K562 Ima vs Ctrl') +
  ylab('Activity modulation LAMA84 Ima vs Ctrl') +
  scale_color_manual(values = color_list)+
  theme_classic() +
  ggpubr::stat_cor() +
  ggrepel::geom_text_repel(size = 3) +
  theme(legend.position = 'bottom', text = element_text(size = 8)) 

Figure 3A Protein activity prediction results. Scatterplots showing the comparison between protein activity predicted in K562 (x-axis) and LAMA84 (y-axis) datasets. Each dot represents a protein, and the color indicates the molecular function: kinases (purple), phosphatases (green), others (violet), and transcription factors (orange). R indicates Pearson correlation.

Network analysis

Nodes table

phenoscore_network <- readRDS('../results/ima_ctrl/pheno_opt1.rds')
DT::datatable(phenoscore_network$nodes_df)

Edges table

phenoscore_network <- readRDS('../results/ima_ctrl/pheno_opt1.rds')
DT::datatable(phenoscore_network$edges_df)
write_tsv(phenoscore_network$edges_df, '../results/ima_ctrl/edges_to_phenotypes.tsv')
Barplot of resulting phenotypes
phenoscore_result <- readRDS('../results/ima_ctrl/phenoscore.rds')
phenoscore_result$barplot

Figure S3F Bar plot of the phenotypic modulation upon imatinib treatment in sensitive cells inferred by SignalingProfiler 2.0. Blue and red bars represent inactive and active phenotypes, respectively.

Functional circuits from BCR-ABL1 to phenotypes

We generated a functional circuit of 37 nodes and 88 edges linking inhibited BCR-ABL to phenotypes.

phenoscore_network <- readRDS('../results/ima_ctrl/pheno_opt1.rds')
phenotypes <- c('APOPTOSIS', 'PROLIFERATION', 'G1_S_TRANSITION', 'DNA_REPAIR', 'CELL_CYCLE_BLOCK', 'CELL_CYCLE_EXIT', 'DNA_FRAGMENTATION')

phenoscore_network <- format_for_visualization(phenoscore_network)

k = 7
circuit <- pheno_to_start_circuit(SP_object = phenoscore_network,
                                    start_nodes = c('BCR_ABL'),
                                    phenotypes = phenotypes,
                                    k = k,
                                    start_to_top = TRUE)

Functional circuit Figure 3B Functional submodel extracted from SignalingProfiler 2.0 output linking BCR-ABL to cellular phenotypes modulated upon imatinib treatment. Highlighted proteins are validated by western blot analysis.

Comparison between K562 and patients

To compare patients and cell lines, we computed the activity of transcription factors from transcriptomics data of patients downloaded from GEO (dataset n.GSE216837)

# Transform RNAseq data in SignalingProfiler compliant format
tr_df_p <- read_tsv('../input/patients_mRNA_ima_ctrl.tsv', show_col_types = FALSE)

tfea_res <- run_footprint_based_analysis(omic_data = tr_df_p,
                                             analysis = 'tfea',
                                             organism = 'human',
                                             reg_minsize = 20,
                                             collectri = TRUE,
                                             exp_sign = FALSE,
                                             hypergeom_corr = TRUE,
                                             GO_annotation = TRUE)

write_tsv(tfea_res, '../results/ima_ctrl/patients_tfs.tsv')
# Compare with k562 TF activity
tfea_res <- read_tsv('../results/ima_ctrl/patients_tfs.tsv', show_col_types = FALSE)

tfs_table <- read_tsv('../results/ima_ctrl/final_score.tsv', show_col_types = FALSE)
tfs_table %>% filter(!is.na(final_score.K562)) %>% filter(mf == 'tf')-> tfs_table_k562

inner_join(tfea_res, tfs_table_k562, by = 'gene_name') -> merged

 merged_TFs <- merged %>% dplyr::select(gene_name, weightedNES,
                                           final_score = final_score.K562)
 
merged_TFs %>% column_to_rownames('gene_name') -> merged_m
merged_m[is.na(merged_m)] <- 0

merged_m %>% rownames_to_column('gene_name') -> merged_TFs
    
ggplot(merged_TFs, aes(x = weightedNES, y = final_score, label = gene_name)) +
      geom_point() +
      geom_hline(yintercept = 0) +
      geom_vline(xintercept = 0) +
      ggrepel::geom_text_repel() +
      xlab('Patients inferred activity modulation') +
      ggpubr::stat_cor() +
      theme_classic() 

Figure 2D Scatterplot of transcription factors’ inferred activity with SignalnigProfiler 2.0 in patients samples from GEO dataset n. GSE216837 (x-axis) and K562 cell line (y-axis) upon imatinib exposure. R represents Pearson correlation.

Resistant cells vs Sensitive cells characterization

Inferred proteins characterization

protein_df <- read_tsv('../results/res_sens/final_score.tsv', show_col_types = FALSE)
DT::datatable(protein_df)

Comparison between Res vs Sens and Ima vs Ctrl

protein_df_rs <- read_tsv('../results/res_sens/final_score.tsv', show_col_types = FALSE)
proteins_df_ima_ctrl <- read_tsv('../results/ima_ctrl/final_score.tsv', show_col_types = FALSE) %>% 
  filter(!is.na(final_score.K562)) %>%
  dplyr::select(UNIPROT = UNIPROT.K562, gene_name, mf, method = method.K562, final_score = final_score.K562)

full_join(proteins_df_ima_ctrl, protein_df_rs, by = c('gene_name', 'mf'), suffix = c('.ima', '.res')) -> all_proteins_df

#write_tsv(all_proteins_df, '../result_clean_bf/matched_ima_res_ctrl.tsv')

all_proteins_df_kin <- all_proteins_df %>% filter(mf == 'kin' | mf == 'phos')

color_list <- list(kin = '#D4145A', phos = '#009245', other = '#BA9BC9', tf = '#F7931E')

ggplot(all_proteins_df_kin, aes(x = final_score.ima, y = final_score.res, label = gene_name)) +
  geom_point(aes(color = mf)) +
  geom_hline(yintercept = 0) +
  geom_vline(xintercept = 0) +
  xlab('Activity modulation K562 Ima vs Ctrl') +
  ylab('Activity modulation Res vs Ctrl') +
  scale_color_manual(values = color_list)+
  theme_classic() +
  ggpubr::stat_cor() +
  ggrepel::geom_text_repel(size = 2) +
  theme(legend.position = 'bottom', text = element_text(size = 8)) 

Figure 4E Scatterplots showing the comparison between kinases activity predicted in Sensitive (x-axis) and Resistant (y-axis) vs Control datasets for kinases and phosphatases. Each dot represents a protein. R indicates Pearson correlation.

BCR-ABL dependent signaling network

ima_ctrl <- readRDS('../results/ima_ctrl/pheno_opt1.rds')
res_sens <- readRDS('../results/res_sens/phenoscore.rds')

ima_ctrl_prot <- ima_ctrl$nodes_df
res_sens_prot <- res_sens$sp_object_phenotypes$nodes_df

inner_join(ima_ctrl_prot, res_sens_prot, by = c('gene_name'), suffix = c('.ima', '.res')) -> joined_prots
joined_prots %>% filter(carnival_activity.res * carnival_activity.ima > 0) -> same_regulation

k1 = 5
targets <- same_regulation$gene_name

res_network_opt <- res_sens$sp_object_phenotypes

pheno_to_start_circuit(SP_object = res_network_opt,
                       start_nodes = c('BCR_ABL'),
                       phenotypes = targets, #c(opposites$gene_name),
                       k = k1) -> circuit_res

as_data_frame(x = circuit_res, what = c('vertices')) -> proteins_res_circuit

k2 = 1
pheno_to_start_circuit(SP_object = res_network_opt,
                       start_nodes =  proteins_res_circuit$name,
                       phenotypes = c('PROLIFERATION', 'APOPTOSIS'), #c(opposites$gene_name),
                       k = k2) -> circuit_res_pheno

# Create the union
pheno_circuit_proteins <- as_data_frame(x = circuit_res_pheno, what = c('vertices'))
sig_circuit_proteins <- as_data_frame(x = circuit_res, what = c('vertices'))
bind_rows(pheno_circuit_proteins, sig_circuit_proteins) %>% distinct() -> union_df_nodes

pheno_circuit_edges<- as_data_frame(x = circuit_res_pheno, what = c('edges'))
sig_circuit_edges <- as_data_frame(x = circuit_res, what = c('edges'))
bind_rows(pheno_circuit_edges, sig_circuit_edges) %>% distinct() -> union_df_edges

graph_from_data_frame(d = union_df_edges, vertices = union_df_nodes) -> final_graph

#write_rds(final_graph, '../results/res_sens/bcr_dependent_network.rds')

RCy3::createNetworkFromIgraph(igraph=final_graph,
                              title = paste0('k1 = ', k1),
                              collection = 'BCR-ABL dependent network')

#data_path <- system.file("extdata", "SP_pheno_layout.xml", package = "SignalingProfiler")
#RCy3::importVisualStyles(filename = data_path)
RCy3::setVisualStyle('SP_pheno_layout')
Visualization of anti-survival axes conserved in resistant cells
bcr_abl_dependent <- readRDS('../results/res_sens/druggability_score/bcr_abl_dependent_res.rds')
nodes_bcr_dep_network <- as_data_frame(bcr_abl_independent, what = 'vertices')
edges_bcr_dep_network <- as_data_frame(bcr_abl_independent, what = 'edges')

# Isolate proteins and phenotypes
proteins_df <- nodes_bcr_dep_network %>% #dplyr::filter(name %in% druggability_result_sub$gene_name) %>%
  dplyr::select(gene_name = name, UNIPROT, final_score = carnival_activity, method, mf) %>%
  filter(!gene_name %in% c('APOPTOSIS', 'PROLIFERATION'))

target_df <- nodes_bcr_dep_network %>% dplyr::filter(name %in% c('APOPTOSIS', 'PROLIFERATION'))
target_df$carnival_activity <- c(100, -100)
target_df <- target_df %>%
  dplyr::select(gene_name = name, UNIPROT, final_score = carnival_activity, method, mf)

# Transform the optimized network edges in SIF format
pheno_naive_df <- edges_bcr_dep_network %>% dplyr::select(source = from, interaction = sign, target = to)

solver = 'cplex'
carnival_options = default_CARNIVAL_options(solver)
output1 <- run_carnival_and_create_graph(source_df = proteins_df ,
                                         target_df = target_df,
                                         naive_network = unique(pheno_naive_df),
                                         proteins_df = nodes_bcr_dep_network %>%
                                           dplyr::select(gene_name = name, UNIPROT, final_score, method, mf),
                                         organism = 'human',
                                         carnival_options = carnival_options,
                                         files = TRUE,
                                         direct = TRUE,
                                         with_atlas = FALSE,
                                         path_sif = '../results/res_sens/dep_circuit_optimized.sif',
                                         path_rds = '../results/res_sens/dep_circuit_optimized.rds')

# Map omics on the optimized model
phospho_df <- read_tsv('../input/phospho_K562_res_sens_SP.tsv')

sp_output_df <- expand_and_map_edges(optimized_object = output1,
                                     organism = 'human',
                                     phospho_df = phospho_df,
                                     files = TRUE,
                                     direct = TRUE,
                                     with_atlas = FALSE,
                                     path_sif = '../results/res_sens/ind_circuit_optimized_validated.sif',
                                     path_rds = '../results/res_sens/ind_circuit_optimized_optimized_validated.rds')

sp_output_df$nodes_df <- sp_output_df$nodes_df %>%
  mutate(gold_standard = ifelse(gene_name %in% same_regulation$gene_name, 'Y', 'N'))

sp_output_df$igraph_network <- graph_from_data_frame(d = sp_output_df$edges_df,
                                                     vertices = sp_output_df$nodes_df)

final_sp_visualization <- format_for_visualization(sp_output_df)

RCy3::createNetworkFromIgraph(igraph=sp_output_df$igraph_network,
                              title = paste0('BCR_ABL dependent network optimized'),
                              #title = paste0('BCR_ABL independent network optimized'),
                              collection = 'BCR_ABL independent')
#Set in Cytoscape the SignalingProfiler style available in SignalingProfiler R package
#data_path <- system.file("extdata", "SP_pheno_layout.xml", package = "SignalingProfiler")
#RCy3::importVisualStyles(filename = data_path)
RCy3::setVisualStyle('SP_pheno_layout')

BCR-ABL dependent signaling axes in K562-R

BCR-ABL independent signaling network

Identification of receptors oppositely modulated in K562-R and sensitive cells

We identified 23 alternative receptors that are resistant cells-specific or have opposite modulation between the two cell lines.

ima_ctrl <- readRDS('../results/ima_ctrl/pheno_opt1.rds')
res_sens <- readRDS('../results/res_sens/phenoscore.rds')

# Annotate with the protein name to look for receptor work
biomartr::getMarts()
gene_set <- opposites_in_networks$gene_name

result_BM <- biomartr::biomart( genes      = unique(gene_set), # genes were retrieved using biomartr::getGenome()
                                mart       = "ENSEMBL_MART_ENSEMBL", # marts were selected with biomartr::getMarts()
                                dataset    = "hsapiens_gene_ensembl", # datasets were selected with biomartr::getDatasets()
                                attributes = c("uniprotswissprot", "description"), # attributes were selected with biomartr::getAttributes()
                                filters    = "hgnc_symbol") # specify what ID type was stored in the fasta file retrieved with biomartr::getGenome()

result_BM  %>% filter(uniprotswissprot != '') -> result_BM_clean
result_BM_clean %>% filter(grepl('receptor', description))  -> receptors_list


left_join(opposites_in_networks, result_BM_clean, by = c('gene_name' = 'hgnc_symbol')) -> opposites_in_networks_anno
opposites_in_networks_anno %>% mutate(receptor = ifelse(gene_name %in% receptors_list$hgnc_symbol, 'y', NA)) -> opposites_in_networks_anno

write_tsv(opposites_in_networks_anno, '../results/res_sens/activated_proteins_network_new.tsv')
opposites_in_networks_anno <- read_tsv( '../results/res_sens/activated_proteins_network_new.tsv', show_col_types = FALSE)
opposites_in_networks_anno %>% filter(receptor == 'y') -> opposites_in_networks_anno_receptr

heatmap_matrix <- opposites_in_networks_anno_receptr %>% dplyr::select(gene_name, carnival_activity.res, carnival_activity.sens) %>%
  column_to_rownames('gene_name')
heatmap_anno <- opposites_in_networks_anno_receptr %>% dplyr::select(gene_name, method.res, method.sens) %>%
  column_to_rownames('gene_name')

paletteLength <-1000
RdBu <- RColorBrewer::brewer.pal(n = 11, 'RdBu')
myColor <- colorRampPalette(c(RdBu[10], "white", RdBu[2]))(paletteLength)

myBreaks <- c(seq(-100, 0, length.out=ceiling(paletteLength/2) +1),
              seq(0, 100, length.out=floor(paletteLength/2)))

p <- pheatmap::pheatmap(t(as.matrix(heatmap_matrix)),
                        color = myColor,
                        border_color = 'white',
                        cellwidth = 8,
                        cellheight = 8,
                        fontsize = 8,
                        cluster_rows = TRUE,
                        cluster_cols = TRUE,
                        breaks = unique(myBreaks),
                        annotation_col = heatmap_anno,
                        show_colnames = T,
                        drop_legends = TRUE)

Figure S6B Heatmap reporting for K562-R and K562 the activity of receptora in SignalingProfiler 2.0 generated networks.

Build BCR-ABL independent signaling network from alternative receptors

These receptors were selected as starting points for functional circuits of maximum path length of 6.

library(igraph)
# Read sensitive and resistant cells networks
ima_ctrl <- readRDS('../results/ima_ctrl/pheno_opt1.rds')
res_sens <- readRDS('../results/res_sens/phenoscore.rds')

# Read receptors with opposite activity table
opposites_in_networks_anno <- read_tsv( '../results/res_sens/activated_proteins_network_new.tsv', show_col_types = FALSE)
opposites_in_networks_anno %>% filter(receptor == 'y') -> opposites_in_networks_anno_receptr
opposites_in_networks_anno %>% filter(is.na(receptor)) -> opposites_in_networks_anno_others

# Change variable names
res_network_opt <- res_sens$sp_object_phenotypes
res_network_opt <- format_for_visualization(res_network_opt)
res_network_opt$nodes_df <- res_network_opt$nodes_df %>%
  mutate(gold_standard = ifelse(gene_name %in%
                                  opposites_in_networks_anno$gene_name, 'Y', NA))
res_network_opt$igraph_network <- graph_from_data_frame(d = res_network_opt$edges_df,
                                                        vertices = res_network_opt$nodes_df)

sens_network_opt <- ima_ctrl
sens_network_opt$igraph_network <- graph_from_data_frame(d = sens_network_opt$edges_df,
                                                         vertices = sens_network_opt$nodes_df)
sens_network_opt <- format_for_visualization(sens_network_opt)

# Isolate opposite proteins
opposites_in_networks_anno_others %>% filter(mf.res != 'phenotype') -> opposites_in_networks_anno_others_new


# Create circuit
k1 = 5

targets <- opposites_in_networks_anno_others_new$gene_name[opposites_in_networks_anno_others_new$gene_name %in% res_network_opt$nodes_df$gene_name]

pheno_to_start_circuit(SP_object = res_network_opt,
                       start_nodes = c('BCR_ABL', opposites_in_networks_anno_receptr$gene_name),
                       phenotypes = targets, #c(opposites$gene_name),
                       k = k1) -> circuit_res

RCy3::createNetworkFromIgraph(igraph=circuit_res,
                              title = paste0('opposites k=', k, ' NEWNEW'),
                              collection = 'Res new receptor up and down')

RCy3::setVisualStyle('SP_pheno_layout')

as_data_frame(x = circuit_res, what = c('vertices')) -> proteins_res_circuit
proteins_res_circuit %>% filter(gold_standard == 'Y') -> proteins_res_circuit_G
k2 = 1

pheno_to_start_circuit(SP_object = res_network_opt,
                       start_nodes =  proteins_res_circuit_G$name,
                       phenotypes = c('PROLIFERATION', 'APOPTOSIS'), #c(opposites$gene_name),
                       k = k2) -> circuit_res_pheno

# Create the union
pheno_circuit_proteins <- as_data_frame(x = circuit_res_pheno, what = c('vertices'))
sig_circuit_proteins <- as_data_frame(x = circuit_res, what = c('vertices'))
bind_rows(pheno_circuit_proteins, sig_circuit_proteins) %>% distinct() -> union_df_nodes

pheno_circuit_edges<- as_data_frame(x = circuit_res_pheno, what = c('edges'))
sig_circuit_edges <- as_data_frame(x = circuit_res, what = c('edges'))
bind_rows(pheno_circuit_edges, sig_circuit_edges) %>% distinct() -> union_df_edges

graph_from_data_frame(d = union_df_edges, vertices = union_df_nodes) -> final_graph

write_rds(final_graph, '../results/res_sens/bcr_independent_network.rds')

RCy3::createNetworkFromIgraph(igraph=final_graph,
                              title = paste0('RES to phenotypes k=', k1),
                              collection = 'Res new new all paths 2')

#data_path <- system.file("extdata", "SP_pheno_layout.xml", package = "SignalingProfiler")
#RCy3::importVisualStyles(filename = data_path)
RCy3::setVisualStyle('SP_pheno_layout')

Visualization of pro-survival signaling axes

To focus on the signaling axes activating proliferation and inhibiting apoptosis, we optimized the BCR-ABL indepenendent network on active proliferation and inactive apoptosis.

bcr_abl_independent <- readRDS('../results/res_sens/bcr_independent_network.rds')
nodes_bcr_ind_network <- as_data_frame(bcr_abl_independent, what = 'vertices')
edges_bcr_ind_network <- as_data_frame(bcr_abl_independent, what = 'edges')

# Isolate proteins and phenotypes
proteins_df <- nodes_bcr_ind_network %>% #dplyr::filter(name %in% druggability_result_sub$gene_name) %>%
  dplyr::select(gene_name = name, UNIPROT, final_score = carnival_activity, method, mf) %>%
  filter(!gene_name %in% c('APOPTOSIS', 'PROLIFERATION'))

target_df <- nodes_bcr_ind_network %>% dplyr::filter(name %in% c('APOPTOSIS', 'PROLIFERATION'))
target_df$carnival_activity <- c(-100, 100)
target_df <- target_df %>%
  dplyr::select(gene_name = name, UNIPROT, final_score = carnival_activity, method, mf)

# Transform the optimized network edges in SIF format
pheno_naive_df <- edges_bcr_ind_network %>% dplyr::select(source = from, interaction = sign, target = to)

solver = 'cplex'
carnival_options = default_CARNIVAL_options(solver)
output1 <- run_carnival_and_create_graph(source_df = proteins_df ,
                                         target_df = target_df,
                                         naive_network = unique(pheno_naive_df),
                                         proteins_df = nodes_bcr_ind_network %>%
                                           dplyr::select(gene_name = name, UNIPROT, final_score, method, mf),
                                         organism = 'human',
                                         carnival_options = carnival_options,
                                         files = TRUE,
                                         direct = TRUE,
                                         with_atlas = FALSE,
                                         path_sif = '../results/res_sens/ind_circuit_optimized.sif',
                                         path_rds = '../results/res_sens/ind_circuit_optimized.rds')

# Map omics on the optimized model
phospho_df <- read_tsv('../input/phospho_K562_res_sens_SP.tsv')

sp_output_df <- expand_and_map_edges(optimized_object = output1,
                                     organism = 'human',
                                     phospho_df = phospho_df,
                                     files = TRUE,
                                     direct = TRUE,
                                     with_atlas = FALSE,
                                       path_sif = '../results/res_sens/ind_circuit_optimized_validated.sif',
                                     path_rds = '../results/res_sens/ind_circuit_optimized_optimized_validated.rds')

sp_output_df$igraph_network <- graph_from_data_frame(d = sp_output_df$edges_df,
                                                     vertices = sp_output_df$nodes_df)

final_sp_visualization <- format_for_visualization(sp_output_df)

RCy3::createNetworkFromIgraph(igraph=sp_output_df$igraph_network,
                              title = paste0('BCR_ABL independent network optimized'),
                              collection = 'BCR_ABL independent')
#Set in Cytoscape the SignalingProfiler style available in SignalingProfiler R package
#data_path <- system.file("extdata", "SP_pheno_layout.xml", package = "SignalingProfiler")
#RCy3::importVisualStyles(filename = data_path)
RCy3::setVisualStyle('SP_pheno_layout')

Then, we can extracted pro-survival circuits with maximum path length 4.

sp_object_net <- readRDS('../results/res_sens/ind_circuit_optimized_optimized_validated.rds')
opposites_in_networks_anno <- read_tsv( '../results/res_sens/activated_proteins_network_new.tsv')

# Format for visualization
sp_object_net$nodes_df <- sp_object_net$nodes_df %>%
  mutate(gold_standard = ifelse(gene_name %in%
                                  opposites_in_networks_anno$gene_name, 'Y', NA))

sp_object_net$igraph_network <- graph_from_data_frame(d = sp_object_net$edges_df,
                                                        vertices = sp_object_net$nodes_df)

sp_object_net <- format_for_visualization(sp_object_net)

k = 4
pheno_to_start_circuit(SP_object = sp_object_net,
                       start_nodes =  c(opposites_in_networks_anno_receptr$gene_name),
                       phenotypes = c('PROLIFERATION', 'APOPTOSIS'), #c(opposites$gene_name),
                       k = k,
                       start_to_top = TRUE) -> circuit_specific

RCy3::createNetworkFromIgraph(igraph=circuit_specific,
                              title = paste0('all rec', ' k = ', k),
                              collection = 'BCR_ABL independent')
RCy3::setVisualStyle('SP_pheno_layout')

BCR-ABL independent signaling axes in K562-R

Druggability score computation

In the druggability score computation, we consider the **topology score* that is combined to the activation status of proteins.

\[topologyscore = degree_{norm}+paths_{apoptosis}+paths_{proliferation}\]

\[druggabilityscore=topologyscore * activity/100\]

Here is reported the code.

# Vector of gene names of FDA-approved drug targets from literature (REF)
dr_nodes <- c("BCL2" , "TNFRSF17" , "BCR_ABL" , "FLT4" , "KDR" , "FLT1" , 
              "FGFR" , "PDGFRA " , "PDGFRB" , "RET" , "KIT" , "TIE2" , "FLT3" , 
              "BTK" , "CCR4" , "CD19" , "MS4A1" , "CD22" , "TNFRSF8" , "CD38" , 
              "CD79B" , "CDA" , "PDGFRA" , "PRKCA" , "AMPK" , "CDK1" , "SYK" , "CRBN" , 
              "DNA_DAMAGE" , "RNMT" , "EZH2" , "AXL" , "ALK" , "IDH1" , "IDH2" ,
              "JAK1" , "JAK2" , "PDCD1" , "Proteasome" , "Protein level" , 
              "SLAMF7" , "SMO receptor" , "SRC" , "ABL1" , "TOP2A" , "Tubulin" , "XPO1" , 
              "DNMT3A" , "PI3K" , "PIK3C2A" , "PIK3C2B" , "PIK3C3" , "PIK3CA" , "PIK3CB" , 
              "PIK3CD" , "PIK3CG" , "PIK3R1" , "PIK3R2" , "PIK3R3" , "DNMT3B" , "DNMT1" , "PARP1")


druggability_network <- readRDS('../results/res_sens/bcr_independent_network.rds')
drugg_net_clean <- remove_nodes_and_interactors(graph = druggability_network)

# Compute the number of inhibitory paths to apoptosis
n_paths_apo <- c()

i_v = 1
for(i_v in c(1:length(V(drugg_net_clean)$name))){

  vertex <- V(drugg_net_clean)$name[i_v]

  all_paths_all <- igraph::all_simple_paths(graph = drugg_net_clean,
                                        from = V(drugg_net_clean)[V(drugg_net_clean)$name == vertex],
                                        to = V(drugg_net_clean)$name[V(drugg_net_clean)$name == 'APOPTOSIS'],
                                        mode = 'out',
                                        cutoff = 10)

  if(length(all_paths_all) != 0){
    all_paths <- filter_paths_raw(graph = drugg_net_clean,
                                  all_paths = all_paths_all,
                                  causality = '-1',mode = 'out')

    # If there are filtered paths and are longer paths than one, keep them because the other is an indirect interaction!
    if(length(all_paths) != 0){
      weighted_sum <- rep(1, length(all_paths)) / unlist(lapply(all_paths, function(x){length(x)}))
      length_i <- mean(weighted_sum)
    }else{
      length_i = 0
    }
  }else{
    length_i = 0
  }

  n_paths_apo <- c(n_paths_apo, length_i)

}

names(n_paths_apo) <- V(drugg_net_clean)$name

# Compute the number of activatory paths to proliferation

n_paths_pro <- c()

for(i_v in c(1:length(V(drugg_net_clean)$name))){

  vertex <- V(drugg_net_clean)$name[i_v]

  all_paths_all <- igraph::all_simple_paths(graph = drugg_net_clean,
                                            from = V(drugg_net_clean)[V(drugg_net_clean)$name == vertex],
                                            to = V(drugg_net_clean)$name[V(drugg_net_clean)$name == 'PROLIFERATION'],
                                            mode = 'out', cutoff = 10)


  if(length(all_paths_all) != 0){

    all_paths <- filter_paths_raw(graph = drugg_net_clean, all_paths = all_paths_all, causality = '1',mode = 'out')

    if(length(all_paths) != 0){
      weighted_sum <- rep(1, length(all_paths)) / unlist(lapply(all_paths, function(x){length(x)}))
      length_i <- mean(weighted_sum)
    }else{
      length_i = 0
    }

  }else{
    length_i = 0
  }

  n_paths_pro <- c(n_paths_pro, length_i)

}

# Create a tibble with the number of paths for proliferation and apoptosis

names(n_paths_apo) <- V(drugg_net_clean)$name
names(n_paths_pro) <- V(drugg_net_clean)$name

tibble(gene_name = names(n_paths_pro),
       n_paths_pro = n_paths_pro,
       n_paths_apo = n_paths_apo) -> paths_df

score_df <- tibble(gene_name = names(degree(drugg_net_clean, mode = 'in')),
                   degree = degree(drugg_net_clean, mode = 'all'),
                   indegree =  degree(drugg_net_clean, mode = 'in'),
                   out_degree =  degree(drugg_net_clean, mode = 'out'),
                   n_paths_apo = paths_df$n_paths_apo,
                   n_paths_pro = paths_df$n_paths_pro,
                   activity = V(drugg_net_clean)$carnival_activity,
                   tested = V(drugg_net_clean)$Sens_final)

score_df %>% mutate(
  norm_degree = log(degree+1)/max(score_df$degree),
  norm_indegree = log(indegree+1)/max(log(score_df$indegree + 1)),
  norm_outdegree = log(out_degree+1)/max(log(score_df$out_degree + 1)),
  norm_n_paths_apo = log(n_paths_apo+1)/max(log(score_df$n_paths_apo + 1)),
  norm_n_paths_pro = log(n_paths_pro+1)/max(log(score_df$n_paths_pro + 1)),
  druggable = ifelse(gene_name %in% dr_nodes, TRUE, FALSE)
) -> score_df

score_df <- score_df %>%
  mutate(topology_score = (norm_indegree + norm_outdegree + norm_n_paths_apo + norm_n_paths_pro)/4)

score_df %>%
  mutate(drug_score = topology_score * activity/100) -> score_df

score_df %>% relocate(gene_name, drug_score, druggable, topology_score) %>%
  arrange(desc(drug_score)) -> score_df

write_tsv(score_df, '../results/res_sens/druggability_score/druggability_score.tsv')

Resulting table

score_df <- readr::read_tsv('../results/res_sens/druggability_score/druggability_score.tsv', show_col_types = FALSE)
DT::datatable(score_df)

Plot

score_df %>%
  mutate(drug_score_norm = drug_score / max(drug_score)) -> score_df

score_df$gene_name1 = fct_reorder(score_df$gene_name,
                                  score_df$drug_score)

score_df %>% filter(druggable == TRUE) -> top_resu
score_df %>% filter(druggable == FALSE) -> bottom_resu

bind_rows(bottom_resu, top_resu) -> score_df_ordered
score_df_ordered <- score_df_ordered %>%
  mutate(label_name = ifelse(druggable == TRUE, as.character(gene_name), ''))

ggplot(score_df_ordered, aes(x = gene_name1, y = drug_score,
                                        color = druggable, label = label_name)) +
  geom_point(size = 1.5, alpha = 0.8) +
  geom_hline(yintercept = 0) +
  ylab('Druggability score in Resistant vs Ctrl') +
  xlab('Gene Name') +
  theme_classic()+
  scale_color_manual(values = c('grey', 'red3')) +
  theme(text = element_text(size = 10),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        legend.position = 'bottom', 
        legend.title = element_blank()) +
  ggrepel::geom_text_repel(max.overlaps = 100) 
## Warning: ggrepel: 1 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

Figure 6B Scatterplot of Druggability Score results where drug targets (x-axis) are ranked according to the Druggability Score (y-axis). Targets of FDA-approved drugs are reported in red.

Experimental validation of druggability score
obs_ic50 <- read_tsv('../results/res_sens/druggability_score/data_validation_druggability.tsv', show_col_types = FALSE)
obs_ic50 %>% column_to_rownames('gene_name') -> obs_ic50_matrix
obs_ic50_matrix_log <- -log2(obs_ic50_matrix)
obs_ic50_matrix_log[is.na(obs_ic50_matrix_log)] <- 0
drugg_score <- obs_ic50_matrix_log %>% rownames_to_column('gene_name') %>%
  mutate(observed = IC50_Res - IC50_Sens)

# Combine the two elements
inner_join(score_df %>%
             dplyr::select(gene_name, drug_score, drug_score_norm),
           drugg_score, by = 'gene_name') -> resulting_df

# Transform in long format
long_df <- resulting_df %>%
  pivot_longer(cols = c('IC50_Sens', 'IC50_Res'))

# PLOT2: validation of druggability score
ggplot(long_df,
       aes(x = drug_score, y = value, color = name, label = gene_name)) +
  geom_point(size = 1.5, alpha = 1) +
  xlab('Druggability score') +
  ylab('-log2(IC50)') +
  geom_hline(yintercept = 0) +
  geom_vline(xintercept = 0) +
  ggrepel::geom_text_repel(max.overlaps = 100) +
  theme_classic() +
  scale_color_manual(values = c('#CD1C67', '#97BDE4')) +
  theme(text = element_text(size = 10),
        legend.position = 'bottom', 
        legend.title = element_blank())

Figure 5D Druggability Score validation according to IC50 derived from MTT viability assays in K562 (blue) and K562-R cells (red).

Conclusion

Aggiungere qui la conclusione del paper

R session info

xfun::session_info()
R version 4.1.2 (2021-11-01)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur 10.16

Locale: en_US.UTF-8 / en_US.UTF-8 / en_US.UTF-8 / C / en_US.UTF-8 / en_US.UTF-8

Package version:
  abind_1.4-5                 ade4_1.7.22                
  airr_1.4.1                  alakazam_1.2.1             
  annotate_1.72.0             AnnotationDbi_1.56.2       
  ape_5.7.1                   askpass_1.1                
  backports_1.4.1             base64enc_0.1.3            
  bcellViper_1.30.0           BH_1.81.0.1                
  Biobase_2.54.0              BiocFileCache_2.2.1        
  BiocGenerics_0.40.0         BiocParallel_1.28.3        
  biomaRt_2.50.3              Biostrings_2.62.0          
  bit_4.0.5                   bit64_4.0.5                
  bitops_1.0-7                blob_1.2.4                 
  boot_1.3.28.1               brio_1.1.3                 
  broom_1.0.5                 bslib_0.5.0                
  cachem_1.0.8                callr_3.7.3                
  car_3.1-2                   carData_3.0-5              
  CARNIVAL_2.7.2              cellranger_1.1.0           
  class_7.3.22                cli_3.6.1                  
  clipr_0.8.0                 cluster_2.1.4              
  colorspace_2.1-0            compiler_4.1.2             
  conflicted_1.2.0            corrplot_0.92              
  cosmosR_1.2.0               cowplot_1.1.1              
  cpp11_0.4.5                 crayon_1.5.2               
  crosstalk_1.2.0             curl_5.0.0                 
  data.table_1.14.8           data.tree_1.0.0            
  DBI_1.1.3                   dbplyr_2.3.3               
  decoupleR_2.5.2             DelayedArray_0.20.0        
  desc_1.4.2                  diffobj_0.3.5              
  digest_0.6.31               dorothea_1.6.0             
  dplyr_1.1.2                 DT_0.28                    
  dtplyr_1.3.1                e1071_1.7.13               
  ellipsis_0.3.2              evaluate_0.21              
  fansi_1.0.4                 farver_2.1.1               
  fastmap_1.1.1               filelock_1.0.2             
  fontawesome_0.5.1           forcats_1.0.0              
  formatR_1.14                fs_1.6.2                   
  futile.logger_1.4.3         futile.options_1.0.1       
  gargle_1.5.2                generics_0.1.3             
  GenomeInfoDb_1.30.1         GenomeInfoDbData_1.2.7     
  GenomicAlignments_1.30.0    GenomicRanges_1.46.1       
  ggforce_0.4.1               ggplot2_3.4.2              
  ggpubr_0.6.0                ggrepel_0.9.3              
  ggsci_3.0.0                 ggsignif_0.6.4             
  glue_1.6.2                  googledrive_2.1.1          
  googlesheets4_1.1.1         gprofiler2_0.2.2           
  graph_1.72.0                graphics_4.1.2             
  grDevices_4.1.2             grid_4.1.2                 
  gridExtra_2.3               GSEABase_1.56.0            
  gtable_0.3.3                haven_2.5.2                
  here_1.0.1                  highr_0.10                 
  hms_1.1.3                   htmltools_0.5.5            
  htmlwidgets_1.6.2           httr_1.4.6                 
  ids_1.0.1                   igraph_1.4.2               
  IRanges_2.28.0              isoband_0.2.7              
  jquerylib_0.1.4             jsonlite_1.8.4             
  KEGGREST_1.34.0             kernlab_0.9.32             
  KernSmooth_2.23.21          knitr_1.43                 
  labeling_0.4.2              lambda.r_1.2.4             
  later_1.3.1                 lattice_0.21.8             
  lazyeval_0.2.2              lifecycle_1.0.3            
  lme4_1.1.33                 lpSolve_5.6.18             
  lubridate_1.9.2             magick_2.7.4               
  magrittr_2.0.3              MASS_7.3.60                
  Matrix_1.5.1                MatrixGenerics_1.6.0       
  MatrixModels_0.5.1          matrixStats_0.63.0         
  memoise_2.0.1               methods_4.1.2              
  mgcv_1.8.42                 mime_0.12                  
  minqa_1.2.5                 mixtools_2.0.0             
  modelr_0.1.11               munsell_0.5.0              
  networkD3_0.4               nlme_3.1.162               
  nloptr_2.0.3                nnet_7.3.19                
  numDeriv_2016.8.1.1         openssl_2.0.6              
  org.Hs.eg.db_3.14.0         parallel_4.1.2             
  parallelly_1.36.0           pbkrtest_0.5.2             
  permute_0.9.7               pheatmap_1.0.12            
  pillar_1.9.0                pixmap_0.4.12              
  pkgconfig_2.0.3             pkgload_1.3.2.1            
  plogr_0.2.0                 plotly_4.10.2              
  plyr_1.8.8                  png_0.1-8                  
  polyclip_1.10.4             polynom_1.4.1              
  praise_1.0.0                prettyunits_1.1.1          
  processx_3.8.1              progress_1.2.2             
  promises_1.2.0.1            proxy_0.4.27               
  ps_1.7.5                    purrr_1.0.1                
  qdapRegex_0.7.5             quantreg_5.95              
  R6_2.5.1                    ragg_1.2.5                 
  rappdirs_0.3.3              RColorBrewer_1.1-3         
  Rcpp_1.0.10                 RcppArmadillo_0.12.2.0.0   
  RcppEigen_0.3.3.9.3         RcppTOML_0.2.2             
  RCurl_1.98-1.12             readr_2.1.4                
  readxl_1.4.2                rematch_1.0.1              
  rematch2_2.1.2              reprex_2.0.2               
  reticulate_1.30.9000        Rhtslib_1.26.0             
  rjson_0.2.21                rlang_1.1.1                
  rmarkdown_2.23              rprojroot_2.0.3            
  Rsamtools_2.10.0            RSQLite_2.3.1              
  rstatix_0.7.2               rstudioapi_0.15.0          
  RVenn_1.1.0                 rvest_1.0.3                
  S4Vectors_0.32.4            sass_0.4.6                 
  scales_1.2.1                segmented_1.6.4            
  selectr_0.4.2               seqinr_4.2.30              
  SignalingProfiler_2.0       snow_0.4.4                 
  sp_1.6.0                    SparseM_1.81               
  splines_4.1.2               stats_4.1.2                
  stats4_4.1.2                stringi_1.7.12             
  stringr_1.5.0               SummarizedExperiment_1.24.0
  survival_3.5.5              sys_3.4.1                  
  systemfonts_1.0.4           testthat_3.1.8             
  textshaping_0.3.6           tibble_3.2.1               
  tidyr_1.3.0                 tidyselect_1.2.0           
  tidyverse_2.0.0             timechange_0.2.0           
  tinytex_0.45                tools_4.1.2                
  tweenr_2.0.2                tzdb_0.3.0                 
  UniprotR_2.2.2              utf8_1.2.3                 
  utils_4.1.2                 uuid_1.1.0                 
  vctrs_0.6.2                 vegan_2.6.4                
  viper_1.28.0                viridisLite_0.4.2          
  visNetwork_2.1.2            vroom_1.6.3                
  waldo_0.5.1                 withr_2.5.0                
  writexl_1.4.2               xfun_0.39                  
  XML_3.99.0.14               xml2_1.3.4                 
  xtable_1.8.4                XVector_0.34.0             
  yaml_2.3.7                  zlibbioc_1.40.0            

References

Adams, Peter. 1993. “The Title of the Work.” The Name of the Journal 4 (2): 201–13.
LS0tCnRpdGxlOiAiQ2hyb25pYyBteWVsb2lkIGxldWtlbWlhIG5vdGVib29rIgphdXRob3I6ICJTYWNjb1BlcmZldHRvTGFiIgpkYXRlOiAiTGFzdCB1cGRhdGVkOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjc3M6IHN0eWxlLmNzcwogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYgpsaW5rLWNpdGF0aW9uczogdHJ1ZQotLS0KCiMgSW50cm8gey51bm51bWJlcmVkfQoKVGVtcGxhdGUgYmFzZWQgb24gW1JtYXJrZG93bl0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLyksIHVzaW5nIHRoZSBbdW5pdGVkIEhUTUwgdGhlbWVdKGh0dHBzOi8vYm9vdHN3YXRjaC5jb20vdW5pdGVkLykuCgpSZWZlciB0byBhIFtzdWIgc2VjdGlvbl0oI3N1Yi1hbmFseXNpcykuIENpdGluZyBhbiBhcnRpY2xlIFtAYXJ0aWNsZV0uIFJlZmVyIHRvIHNlY3Rpb24gW0FuYWx5c2lzXS4KCiMgSW5wdXQgey51bm51bWJlcmVkfQoKTG9hZGluZyBsaWJyYXJpZXM6CgpgYGB7ciBMb2FkIGxpYnJhcmllcywgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KERUKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoeGZ1bikKbGlicmFyeShTaWduYWxpbmdQcm9maWxlcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoaWdyYXBoKQpzb3VyY2UoJy4vMC5saWJyYXJpZXMuUicpCmBgYAoKIyBSdW4gU2lnbmFsaW5nUHJvZmlsZXIgMi4wIGluIGJvdGggY29uZGl0aW9ucwoKYGBge3IgZXZhbCA9IEZBTFNFfQphbmFseXNlcyA8LSBjKCdpbWFfY3RybCcsICdyZXNfc2VucycpCmNlbGxfbGluZXMgPC0gYygnTEFNQTg0JywgJ0s1NjInKQoKc29sdmVyID0gJ2NwbGV4JwpjYXJuaXZhbF9vcHRpb25zID0gZGVmYXVsdF9DQVJOSVZBTF9vcHRpb25zKHNvbHZlcikKCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICMKIyBQcm90ZWluIGFjdGl2aXR5IGluZmVyZW5jZQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAjCgpmb3IoYW5hbHlzaXMgaW4gYW5hbHlzZXMpewoKICBmb3IoY2VsbF9saW5lIGluIGNlbGxfbGluZXMpewoKICAgIHBob3NwaG9fZGYgPC0gcmVhZF90c3YocGFzdGUwKCcuLi9pbnB1dC9waG9zcGhvXycsIGNlbGxfbGluZSwgJ18nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2lmIEs1NjIgc2Vuc19yZXMgYW5kIGltYV9jdHJsLCBpZiBMQU1BIGp1c3QgaW1hX2N0cmwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjZWxsX2xpbmUgPT0gJ0s1NjInLCBhbmFseXNpcywgJ2ltYV9jdHJsJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnX1NQLnRzdicpKQoKICAgIHByb3RfZGYgPC0gcmVhZF90c3YocGFzdGUwKCcuLi9pbnB1dC9wcm90XycsIGNlbGxfbGluZSwgJ18nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2lmIEs1NjIgc2Vuc19yZXMgYW5kIGltYV9jdHJsLCBpZiBMQU1BIGp1c3QgaW1hX2N0cmwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjZWxsX2xpbmUgPT0gJ0s1NjInLCBhbmFseXNpcywgJ2ltYV9jdHJsJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnX1NQLnRzdicpKQoKICAgICMgS2luYXNlIEFjdGl2aXR5IEluZmVyZW5jZQogICAga2luX3Bob3NfYWN0aXZpdHlfZm9vdCA8LSBydW5fZm9vdHByaW50X2Jhc2VkX2FuYWx5c2lzKG9taWNfZGF0YSA9IHBob3NwaG9fZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5hbHlzaXMgPSAna3NlYScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAnaHVtYW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ19taW5zaXplID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBfc2lnbiA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludGVncmF0ZWRfcmVndWxvbnMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGh5cGVyZ2VvbV9jb3JyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHT19hbm5vdGF0aW9uID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyZWN0X3Byb3Rlb21pY3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3RfZGYgPSBwcm90X2RmKQoKICAgICMgSW5mZXIgYWN0aXZpdHkgZnJvbSByZWd1bGF0b3J5IHBob3NwaG9zaXRlcwogICAgcGhvc3Bob3Njb3JlX2RmIDwtIHBob3NwaG9zY29yZV9jb21wdXRhdGlvbihwaG9zcGhvcHJvdGVvbWljX2RhdGEgPSBwaG9zcGhvX2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICdodW1hbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2YXRvcnkgPSBUUlVFICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR09fYW5ub3RhdGlvbiA9IFRSVUUpCgogICAgIyBDb21iaW5lIGZvb3RwcmludC0gYW5kIFBob3NwaG9TY29yZQogICAgY29tYmluZWRfa2luX3Bob3MgPC0gY29tYmluZV9mb290cHJpbnRfYW5kX3Bob3NwaG9zY29yZShmb290cHJpbnRfb3V0cHV0ID0ga2luX3Bob3NfYWN0aXZpdHlfZm9vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGhvc3Bob3Njb3JlX2RmID0gIHBob3NwaG9zY29yZV9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5hbHlzaXMgPSAgJ2tzZWEnKQoKICAgIHRveV9raW4gPC0gY29tYmluZWRfa2luX3Bob3MKICAgIHRveV9vdGhlciA8LSBwaG9zcGhvc2NvcmVfZGYgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIoIW1mICVpbiUgYygna2luJywgJ3Bob3MnLCAndGYnKSkgJT4lCiAgICAgIGRwbHlyOjpyZW5hbWUoZmluYWxfc2NvcmUgPSBwaG9zcGhvc2NvcmUpICU+JQogICAgICBkcGx5cjo6bXV0YXRlKG1ldGhvZCA9ICdQaG9zcGhvU2NvcmUnKQoKICAgIHRveV90ZiA8LSBwaG9zcGhvc2NvcmVfZGYgJT4lCiAgICAgIGRwbHlyOjpmaWx0ZXIobWYgPT0gJ3RmJykKICAgIHRveV90ZiRmaW5hbF9zY29yZSA8LSB0b3lfdGYkcGhvc3Bob3Njb3JlCiAgICB0b3lfdGYkbWV0aG9kID0gJ1Bob3NwaG9TY29yZScKCiAgICAjIGNyZWF0ZSBhIHVuaWZpZWQgJ2FjdGl2aXR5IG1vZHVsYXRpb24nIHRhYmxlIGZvciB0aGUgbmV4dCBzdGVwcwogICAgcHJvdF9hY3Rpdml0eV9kZiA8LSBkcGx5cjo6YmluZF9yb3dzKHRveV9raW4sIHRveV9vdGhlciwgdG95X3RmKSAlPiUKICAgICAgZHBseXI6OnNlbGVjdChVTklQUk9ULCBnZW5lX25hbWUsIG1mLCBmaW5hbF9zY29yZSwgbWV0aG9kKQoKICAgICMjIFByb3Rlb1Njb3JlCiAgICBwcm90ZW9fc2NvcmVfZGYgPC0KICAgICAgU2lnbmFsaW5nUHJvZmlsZXI6OmFjdGl2aXR5X2Zyb21fcHJvdGVvbWljcyhwcm90X2RmID0gcHJvdF9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJodW1hbiIpCgogICAgIyMgQ29tYmluZSBQcm90ZW9TY29yZSBhbmQgQWN0aXZpdGllcwoKICAgIGFjdGl2aXR5X3Byb3Rlb19jb21iaW5lZF9maWx0ZXJlZCA8LQogICAgICBTaWduYWxpbmdQcm9maWxlcjo6Y29tYmluZV9hY3Rpdml0eXNjb3JlX3Byb3Rlb3Njb3JlKGFjdGl2aXR5X3Njb3JlID0gcHJvdF9hY3Rpdml0eV9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm90ZW9fc2NvcmUgPSBwcm90ZW9fc2NvcmVfZGYpCiAgICBhY3Rpdml0eV9wcm90ZW9fY29tYmluZWRfZmlsdGVyZWQkZmluYWxfc2NvcmUgPC0KICAgICAgYXMubnVtZXJpYyhhY3Rpdml0eV9wcm90ZW9fY29tYmluZWRfZmlsdGVyZWQkZmluYWxfc2NvcmUpCgogICAgcHJvdF9hY3Rpdml0eV90b3RhbF9kZiA8LSBhY3Rpdml0eV9wcm90ZW9fY29tYmluZWRfZmlsdGVyZWQKCiAgICBpZihjZWxsX2xpbmUgPT0gJ0s1NjInKXsKICAgICAgazU2Ml9kZiA8LSBwcm90X2FjdGl2aXR5X3RvdGFsX2RmCiAgICB9ZWxzZXsKICAgICAgbGFtYTg0X2RmIDwtIHByb3RfYWN0aXZpdHlfdG90YWxfZGYKICAgIH0KICB9CgogIGlmKGFuYWx5c2lzID09ICdpbWFfY3RybCcpewoKICAgIGZ1bGxfam9pbihrNTYyX2RmLCBsYW1hODRfZGYsIGJ5ID0gYygnZ2VuZV9uYW1lJywgJ21mJyksIHN1ZmZpeCA9IGMoJy5LNTYyJywgJy5MQU1BODQnKSkgLT4gbWVyZ2VkX3RhYmxlCgogICAgIyBnZ3Bsb3QobWVyZ2VkX3RhYmxlLCBhZXMoeCA9IGZpbmFsX3Njb3JlLks1NjIsIHkgPSBmaW5hbF9zY29yZS5MQU1BODQpKSArCiAgICAjICAgZ2VvbV9wb2ludCgpICsKICAgICMgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgICAjICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkKCiAgICBtZXJnZWRfdGFibGUgPC0gbWVyZ2VkX3RhYmxlICU+JSBtdXRhdGUoY29uYyA9IGZpbmFsX3Njb3JlLks1NjIgKiBmaW5hbF9zY29yZS5MQU1BODQpCgogICAgd3JpdGVfdHN2KG1lcmdlZF90YWJsZSwgcGFzdGUwKCcuLi9yZXN1bHRzLycsIGFuYWx5c2lzLCAnL2ZpbmFsX3Njb3JlLnRzdicpKQoKICB9IGVsc2UgewoKICAgIHdyaXRlX3Rzdihwcm90X2FjdGl2aXR5X3RvdGFsX2RmLCBwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvZmluYWxfc2NvcmUudHN2JykpCgogIH0KCn0KCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICMKIyBOZXR3b3JrIGNyZWF0aW9uIGFuZCBvcHRpbWl6YXRpb24KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gIwoKZm9yKGFuYWx5c2lzIGluIGFuYWx5c2VzKXsKICBpZihhbmFseXNpcyA9PSAnaW1hX2N0cmwnKXsKICAgIHByb3RfZGZfbGFtYSA8LSAgcmVhZF90c3YocGFzdGUwKCcuLi9pbnB1dC9wcm90X0xBTUE4NF9pbWFfY3RybF9TUC50c3YnKSkKICAgIHBob3NwaG9fZGZfbGFtYSA8LSByZWFkX3RzdihwYXN0ZTAoJy4uL2lucHV0L3Bob3NwaG9fTEFNQTg0X2ltYV9jdHJsX1NQLnRzdicpKQogICAgcHJvdF9kZl9rNTYyIDwtICByZWFkX3RzdihwYXN0ZTAoJy4uL2lucHV0L3Byb3RfSzU2Ml9pbWFfY3RybF9TUC50c3YnKSkKICAgIHBob3NwaG9fZGZfazU2MiA8LSByZWFkX3RzdihwYXN0ZTAoJy4uL2lucHV0L3Bob3NwaG9fSzU2Ml9pbWFfY3RybF9TUC50c3YnKSkKCiAgICBiaW5kX3Jvd3MocHJvdF9kZl9sYW1hLCBwcm90X2RmX2s1NjIpICU+JSBkaXN0aW5jdChnZW5lX25hbWUpIC0+IHByb3RfZGYKICAgIGJpbmRfcm93cyhwaG9zcGhvX2RmX2xhbWEsIHBob3NwaG9fZGZfazU2MikgJT4lIGRpc3RpbmN0KGdlbmVfbmFtZSkgLT4gcGhvc3Bob19kZgoKICAgICMgUmVhZCBtZXJnZWQgYWN0aXZpdHkKICAgIG1lcmdlZF90YWJsZSA8LSByZWFkX3RzdihwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvZmluYWxfc2NvcmUudHN2JykpCiAgICBhY3Rpdml0eV9kZiA8LSBtZXJnZWRfdGFibGUgJT4lIGZpbHRlcihjb25jID4gMCkgIyB0YWtlIG9ubHkgY29uc2lzdGVudCBwcm90ZWlucwoKICAgIGFjdGl2aXR5X2RmICU+JQogICAgICBmaWx0ZXIobWV0aG9kLks1NjIgIT0gJ3Byb3Rlb3Njb3JlJyB8IG1ldGhvZC5MQU1BODQgIT0gJ3Byb3Rlb3Njb3JlJykgLT4gYm90aF9ub3RfcHJvdGVvCgogICAgYWN0aXZpdHlfZGYgJT4lCiAgICAgIGZpbHRlcigobWV0aG9kLks1NjIgPT0gJ3Byb3Rlb3Njb3JlJyB8IG1ldGhvZC5MQU1BODQgPT0gJ3Byb3Rlb3Njb3JlJykgJiBtZiA9PSAndGYnKSAtPiBwcm90ZW9fdGYKCiAgICBiaW5kX3Jvd3MocHJvdGVvX3RmLCBib3RoX25vdF9wcm90ZW8pIC0+IGFjdGl2aXR5X2RmX3RvdAogIH1lbHNlewogICAgcGhvc3Bob19kZiA8LSByZWFkX3RzdihwYXN0ZTAoJy4uL2lucHV0L3Bob3NwaG9fSzU2Ml8nLCBhbmFseXNpcywgJ19TUC50c3YnKSkKICAgIHByb3RfZGYgPC0gcmVhZF90c3YocGFzdGUwKCcuLi9pbnB1dC9wcm90X0s1NjJfJywgYW5hbHlzaXMsICdfU1AudHN2JykpCgogICAgYWN0aXZpdHlfZGZfdG90IDwtIHJlYWRfdHN2KHBhc3RlMChwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvZmluYWxfc2NvcmUudHN2JykpKQogIH0KCiAgIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAjCiAgIyBCdWlsZCBuYWl2ZSBuZXR3b3JrCiAgIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAjCgogICAjICMgUEtOIHByZXByb2Nlc3NpbmcKICAgIFBLTl90YWJsZSA8LSBjaG9vc2VfUEtOKG9yZ2FuaXNtID0gJ2h1bWFuJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhfYXRsYXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXN0b20gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9wYXRoID0gTlVMTCkKCiAgICAjIFByZXByb2Nlc3MgYWNjb3JkaW5nIHRvIHRoZSBkaWZmZXJlbnQgY29uZGl0aW9uCiAgICBQS05fZXhwcmVzc2VkIDwtIHByZXByb2Nlc3NfUEtOKG9taWNzX2RhdGEgPSBsaXN0KHByb3RfZGYsIHBob3NwaG9fZGYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQS05fdGFibGUgPSBQS05fdGFibGUpCgogICAgIyBJbiB0aGUgdHdvLWxheWVyZWQgbmV0d29yayBzZXBhcmF0ZSBLSU4vUEhPUy9PVEhFUnMgYW5kIFRGcwogICAga2luX3Bob3Nfb3RoZXIgPC0gYWN0aXZpdHlfZGZfdG90ICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKG1mICVpbiUgYygna2luJywgJ3Bob3MnLCAnb3RoZXInKSkKCiAgICB0ZnMgPC0gYWN0aXZpdHlfZGZfdG90ICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKG1mID09ICd0ZicpCgoKICAgIG5haXZlX25ldHdvcmsgPC0gdHdvX2xheWVyX25haXZlX25ldHdvcmsoc3RhcnRzX2duID0gYygnQkNSX0FCTCcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcm1lZGlhdGVfZ24gPSBraW5fcGhvc19vdGhlciRnZW5lX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldHNfZ24gPSB0ZnMkZ2VuZV9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQS05fdGFibGUgPSBQS05fZXhwcmVzc2VkLCAjb3IgUEtOX2h1bWFuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heF9sZW5ndGhfMSA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heF9sZW5ndGhfMiA9IDQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3RfYWxsID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmRzX3BhdGggPSBwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvbmFpdmVfbmV0d29yay5yZHMnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2lmX3BhdGggPSBwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvbmFpdmVfbmV0d29yay5zaWYnKSkKCiAgIyA9PT09PT09PT09PT09PT09PT09PT0gIwogICMgQ0FSTklWQUwgb3B0aW1pemF0aW9uCiAgIyA9PT09PT09PT09PT09PT09PT09PT0gIwogIG5haXZlX25ldHdvcmsgPC0gcmVhZFJEUyhwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvbmFpdmVfbmV0d29yay5yZHMnKSkKICAjIFNldCByZWNlcHRvciBsaXN0CiAgcmVjZXB0b3JfbGlzdCA8LSBsaXN0KCdCQ1JfQUJMJyA9IC0xKQoKICBpZihhbmFseXNpcyA9PSAnaW1hX2N0cmwnKXsKCiAgICAjIEdldCBhbmQgcGFyc2UgcHJvdGVpbiBhY3Rpdml0eQogICAgYWN0aXZpdHlfZGZfZm9yX2Nhcm5pdmFsIDwtIGFjdGl2aXR5X2RmX3RvdCAlPiUgbXV0YXRlKG1ldGhvZCA9IHBhc3RlMChtZXRob2QuSzU2MiwgJzsnLCBtZXRob2QuTEFNQTg0KSkgJT4lCiAgICAgIHJvd3dpc2UoKSAlPiUKICAgICAgbXV0YXRlKGZpbmFsX3Njb3JlID0gbWVhbihjX2Fjcm9zcyhjKGZpbmFsX3Njb3JlLks1NjIsIGZpbmFsX3Njb3JlLks1NjIpKSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgZHBseXI6OnNlbGVjdChVTklQUk9UID0gVU5JUFJPVC5LNTYyLCBnZW5lX25hbWUsIG1mLCBtZXRob2QsIGZpbmFsX3Njb3JlKQoKICAgICMgR2V0IGFuZCBwYXJzZSBQaG9zcGhvcHJvdGVvbWljcwogICAgcHJvdF9kZl9sYW1hIDwtICByZWFkX3RzdihwYXN0ZTAoJy4uL2lucHV0L3Byb3RfTEFNQTg0X2ltYV9jdHJsX1NQLnRzdicpKQogICAgcGhvc3Bob19kZl9sYW1hIDwtIHJlYWRfdHN2KHBhc3RlMCgnLi4vaW5wdXQvcGhvc3Bob19MQU1BODRfaW1hX2N0cmxfU1AudHN2JykpCiAgICBwcm90X2RmX2s1NjIgPC0gIHJlYWRfdHN2KHBhc3RlMCgnLi4vaW5wdXQvcHJvdF9LNTYyX2ltYV9jdHJsX1NQLnRzdicpKQogICAgcGhvc3Bob19kZl9rNTYyIDwtIHJlYWRfdHN2KHBhc3RlMCgnLi4vaW5wdXQvcGhvc3Bob19LNTYyX2ltYV9jdHJsX1NQLnRzdicpKQoKICAgIGlubmVyX2pvaW4ocGhvc3Bob19kZl9rNTYyLCBwaG9zcGhvX2RmX2xhbWEsIGJ5ID0gYygnZ2VuZV9uYW1lJywgJ1VOSVBST1QnLCAnYW1pbm9hY2lkJywgJ3Bvc2l0aW9uJywgJ3NpZ25pZmljYW50JyksCiAgICAgICAgICAgICAgIHN1ZmZpeCA9IGMoJy5LNTYyJywgJy5MQU1BODQnKSkgLT4gam9pbmVkX29taWNzCgogICAgYWdyZWVkX3Bob3NwaG9fZGYgPC0gam9pbmVkX29taWNzICU+JSBtdXRhdGUoY29uYyA9IGRpZmZlcmVuY2UuSzU2MipkaWZmZXJlbmNlLkxBTUE4NCkgJT4lIGZpbHRlcihjb25jID4gMCkKCiAgICBhZ3JlZWRfcGhvc3Bob19kZl9maW5hbCA8LSBhZ3JlZWRfcGhvc3Bob19kZiAlPiUKICAgICAgcm93d2lzZSgpICU+JQogICAgICBtdXRhdGUoZmluYWxfc2NvcmUgPSBtZWFuKGNfYWNyb3NzKGMoZGlmZmVyZW5jZS5LNTYyLCBkaWZmZXJlbmNlLkxBTUE4NCkpLCBuYS5ybSA9IFRSVUUpKSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBkcGx5cjo6c2VsZWN0KFVOSVBST1QsIGdlbmVfbmFtZSwgYW1pbm9hY2lkLCBwb3NpdGlvbiwgZGlmZmVyZW5jZSA9IGZpbmFsX3Njb3JlLAogICAgICAgICAgICAgICAgICAgIHNlcXVlbmNlX3dpbmRvdyA9IHNlcXVlbmNlX3dpbmRvdy5MQU1BODQsIHNpZ25pZmljYW50LCBsb2dwdmFsID0gbG9ncHZhbC5LNTYyKQoKICAgIHBob3NwaG9fZGYgPC0gYWdyZWVkX3Bob3NwaG9fZGZfZmluYWwKICAgIGJpbmRfcm93cyhwcm90X2RmX2xhbWEsIHByb3RfZGZfazU2MikgJT4lIGRpc3RpbmN0KGdlbmVfbmFtZSkgLT4gcHJvdF9kZl93aG9sZQogICAgYmluZF9yb3dzKHBob3NwaG9fZGZfbGFtYSwgcGhvc3Bob19kZl9rNTYyKSAlPiUgZGlzdGluY3QoZ2VuZV9uYW1lKSAtPiBwaG9zcGhvX2RmX3dob2xlCgogIH1lbHNlewoKICAgIGFjdGl2aXR5X2RmX2Zvcl9jYXJuaXZhbCA8LSBhY3Rpdml0eV9kZl90b3QKCiAgICAjIEdldCBQaG9zcGhvcHJvdGVvbWljcwogICAgcGhvc3Bob19kZiA8LSByZWFkX3RzdihwYXN0ZTAoJy4uL2lucHV0L3Bob3NwaG9fSzU2Ml8nLCBhbmFseXNpcywgJ19TUC50c3YnKSkKICB9CgoKICBjYXJuaXZhbF9pbnB1dF90YWJsZSA8LSBwcmVwYXJlX2Nhcm5pdmFsX2lucHV0KG5haXZlX25ldHdvcmssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpdml0eV9kZl9mb3JfY2Fybml2YWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNlcHRvcl9saXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAnaHVtYW4nKQoKICAjICMgRklSU1QgUlVOOiBSRUNFUFRPUiB0byBLSU4sIFBIT1MsIE9USEVSUwogIHJlY2VwdG9yc19kZiA8LSBjYXJuaXZhbF9pbnB1dF90YWJsZSAlPiUgZHBseXI6OmZpbHRlcihtZiA9PSAncmVjJykKCiAgdGFyZ2V0MV9kZiA8LSBjYXJuaXZhbF9pbnB1dF90YWJsZSAlPiUKICAgIGRwbHlyOjpmaWx0ZXIobWYgJWluJSBjKCdraW4nLCAncGhvcycsICdvdGhlcicpKQoKICBuYWl2ZV9uZXR3b3JrX2RmIDwtIHJlYWRyOjpyZWFkX3RzdihwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvbmFpdmVfbmV0d29yay5zaWYnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCdzb3VyY2UnLCAnaW50ZXJhY3Rpb24nLCAndGFyZ2V0JykpCiAgCiAgb3V0cHV0MSA8LSBydW5fY2Fybml2YWxfYW5kX2NyZWF0ZV9ncmFwaChzb3VyY2VfZGYgPSByZWNlcHRvcnNfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldF9kZiA9IHRhcmdldDFfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5haXZlX25ldHdvcmsgPSB1bmlxdWUobmFpdmVfbmV0d29ya19kZiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3RlaW5zX2RmID0gY2Fybml2YWxfaW5wdXRfdGFibGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gJ2h1bWFuJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2Fybml2YWxfb3B0aW9ucyA9IGNhcm5pdmFsX29wdGlvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhfYXRsYXMgPSBGQUxTRSkKCiAgIyBTRUNPTkQgUlVOOiBmcm9tIEtJTiwgUEhPUywgT1RIRVJTIHRvIFRGcwogIHJ1bjFfb3V0cHV0X25vZGVzIDwtIGNvbnZlcnRfb3V0cHV0X25vZGVzX2luX25leHRfaW5wdXQob3V0cHV0MSkKICBydW4xX291dHB1dF9ub2RlcyRVTklQUk9UIDwtICcnCgogIHNvdXJjZV9kZiA8LSBydW4xX291dHB1dF9ub2RlcyAlPiUKICAgIGRwbHlyOjpmaWx0ZXIobWYgJWluJSBjKCdraW4nLCAncGhvcycsICdvdGhlcicpKQoKICB0YXJnZXQyX2RmIDwtIGNhcm5pdmFsX2lucHV0X3RhYmxlICU+JQogICAgZHBseXI6OmZpbHRlcihtZiA9PSAndGYnKQoKICBvdXRwdXQyIDwtIHJ1bl9jYXJuaXZhbF9hbmRfY3JlYXRlX2dyYXBoKHNvdXJjZV9kZiA9IHNvdXJjZV9kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldF9kZiA9IHRhcmdldDJfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYWl2ZV9uZXR3b3JrID0gdW5pcXVlKG5haXZlX25ldHdvcmtfZGYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdGVpbnNfZGYgPSBjYXJuaXZhbF9pbnB1dF90YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gJ2h1bWFuJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhcm5pdmFsX29wdGlvbnMgPSBjYXJuaXZhbF9vcHRpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhfYXRsYXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzID0gRkFMU0UpCgogICMgVU5JT04gT0YgUlVOMSBhbmQgUlVOMiBncmFwaHMKICB1bmlvbiA8LSB1bmlvbl9vZl9ncmFwaHMoZ3JhcGhfMSA9IG91dHB1dDEkaWdyYXBoX25ldHdvcmssCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYXBoXzIgPSBvdXRwdXQyJGlncmFwaF9uZXR3b3JrLAogICAgICAgICAgICAgICAgICAgICAgICAgICBwcm90ZWluc19kZiA9IGNhcm5pdmFsX2lucHV0X3RhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfc2lmID0gcGFzdGUwKCcuLi9yZXN1bHRzLycsIGFuYWx5c2lzLCAnL21lcmdlZC5zaWYnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aF9yZHMgPSBwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvbWVyZ2VkLnJkcycpKQoKICBzcF9vdXRwdXRfZGYgPC0gZXhwYW5kX2FuZF9tYXBfZWRnZXMob3B0aW1pemVkX29iamVjdCA9IHNwX291dHB1dCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAnaHVtYW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaG9zcGhvX2RmID0gcGhvc3Bob19kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3QgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoX2F0bGFzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfc2lmID0gcGFzdGUwKCcuLi9yZXN1bHRzLycsIGFuYWx5c2lzLCAnL3ZhbGlkYXRlZC5zaWYnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aF9yZHMgPSBwYXN0ZTAoJy4uL3Jlc3VsdHMvJywgYW5hbHlzaXMsICcvdmFsaWRhdGVkLnJkcycpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKfQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gIwojIFBoZW5vU2NvcmUgY29tcHV0YXRpb24KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gIwoKIyBJbWEgdnMgQ3RybApwcm90X2RmX2xhbWEgPC0gIHJlYWRfdHN2KHBhc3RlMCgnLi4vaW5wdXQvcHJvdF9MQU1BODRfaW1hX2N0cmxfU1AudHN2JykpCnBob3NwaG9fZGZfbGFtYSA8LSByZWFkX3RzdihwYXN0ZTAoJy4uL2lucHV0L3Bob3NwaG9fTEFNQTg0X2ltYV9jdHJsX1NQLnRzdicpKQpwcm90X2RmX2s1NjIgPC0gIHJlYWRfdHN2KHBhc3RlMCgnLi4vaW5wdXQvcHJvdF9LNTYyX2ltYV9jdHJsX1NQLnRzdicpKQpwaG9zcGhvX2RmX2s1NjIgPC0gcmVhZF90c3YocGFzdGUwKCcuLi9pbnB1dC9waG9zcGhvX0s1NjJfaW1hX2N0cmxfU1AudHN2JykpCgppbm5lcl9qb2luKHBob3NwaG9fZGZfazU2MiwgcGhvc3Bob19kZl9sYW1hLCBieSA9IGMoJ2dlbmVfbmFtZScsICdVTklQUk9UJywgJ2FtaW5vYWNpZCcsICdwb3NpdGlvbicsICdzaWduaWZpY2FudCcpLAogICAgICAgICAgIHN1ZmZpeCA9IGMoJy5LNTYyJywgJy5MQU1BODQnKSkgLT4gam9pbmVkX29taWNzCgphZ3JlZWRfcGhvc3Bob19kZiA8LSBqb2luZWRfb21pY3MgJT4lIG11dGF0ZShjb25jID0gZGlmZmVyZW5jZS5LNTYyKmRpZmZlcmVuY2UuTEFNQTg0KSAlPiUgZmlsdGVyKGNvbmMgPiAwKQoKYWdyZWVkX3Bob3NwaG9fZGZfZmluYWwgPC0gYWdyZWVkX3Bob3NwaG9fZGYgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZShmaW5hbF9zY29yZSA9IG1lYW4oY19hY3Jvc3MoYyhkaWZmZXJlbmNlLks1NjIsIGRpZmZlcmVuY2UuTEFNQTg0KSksIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBkcGx5cjo6c2VsZWN0KFVOSVBST1QsIGdlbmVfbmFtZSwgYW1pbm9hY2lkLCBwb3NpdGlvbiwgZGlmZmVyZW5jZSA9IGZpbmFsX3Njb3JlLAogICAgICAgICAgICAgICAgc2VxdWVuY2Vfd2luZG93ID0gc2VxdWVuY2Vfd2luZG93LkxBTUE4NCwgc2lnbmlmaWNhbnQsIGxvZ3B2YWwgPSBsb2dwdmFsLks1NjIpCgpiaW5kX3Jvd3MocHJvdF9kZl9sYW1hLCBwcm90X2RmX2s1NjIpICU+JSBkaXN0aW5jdChnZW5lX25hbWUpIC0+IHByb3RfZGZfd2hvbGUKYmluZF9yb3dzKHBob3NwaG9fZGZfbGFtYSwgcGhvc3Bob19kZl9rNTYyKSAlPiUgZGlzdGluY3QoZ2VuZV9uYW1lKSAtPiBwaG9zcGhvX2RmX3dob2xlCgojIFNlbGVjdCBhbHNvIHRoZSBkZXNpcmVkIHBoZW5vdHlwZXMKZGVzaXJlZF9waGVub3R5cGVzIDwtIHJlYWRfdHN2KCcuLi9pbnB1dC9waGVub3R5cGVzX2RmX25ldy50c3YnKSAlPiUgZmlsdGVyKHNlbGVjdGlvbiA9PSAneCcpCnBoZW5vX3RhYmxlX2Rpc3RhbmNlcyA8LSBwaGVub3Njb3JlX25ldHdvcmtfcHJlcHJvY2Vzc2luZyhwcm90ZW9taWNzID0gcHJvdF9kZl93aG9sZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBob3NwaG8gPSBwaG9zcGhvX2RmX3dob2xlKQoKYW5hbHlzZXMgPC0gYygnaW1hX2N0cmwnLCAncmVzX3NlbnMnKQoKZm9yKGFuYWx5c2lzIGluIGFuYWx5c2VzKXsKCiAgaWYoYW5hbHlzaXMgPT0gJ2ltYV9jdHJsJyl7CiAgICBwaG9zcGhvX2RmIDwtIGFncmVlZF9waG9zcGhvX2RmX2ZpbmFsCgogIH1lbHNlewogICAgcGhvc3Bob19kZiA8LSByZWFkX3RzdignLi4vaW5wdXQvcGhvc3Bob19LNTYyX3Jlc19zZW5zX1NQLnRzdicpCiAgfQogIAogICBpbnB1dF9wYXRoIDwtIHBhc3RlMCgnLi4vcmVzdWx0cy8nLCBhbmFseXNpcykKCiAgICBzcF9vdXRwdXQgPC0gcmVhZF9yZHMocGFzdGUwKGlucHV0X3BhdGgsICcvdmFsaWRhdGVkLnJkcycpKQoKICAgIHNwX291dHB1dCRpZ3JhcGhfbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IHNwX291dHB1dCRlZGdlc19kZiwgdmVydGljZXMgPSBzcF9vdXRwdXQkbm9kZXNfZGYpCgoKICAgICNzcF9ncmFwaCA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IHNwX291dHB1dCRlZGdlc19kZiAlPiUgbXV0YXRlX2F0KCdzaWduJywgYXMuY2hhcmFjdGVyKSwgdmVydGljZXMgPSBzcF9vdXRwdXQkbm9kZXNfZGYpCgogICAgIyBzcF9vdXRwdXQkbm9kZXNfZGYgPC0gc3Bfb3V0cHV0JG5vZGVzX2RmICU+JSBtdXRhdGUoZmluYWxfc2NvcmUgPSBpZmVsc2UoZGlzY29yZGFudCA9PSBUUlVFLCBOQSwgZmluYWxfc2NvcmUpKQogICAgc3Bfb3V0cHV0JGVkZ2VzX2RmICU+JSBtdXRhdGVfYXQoJ3NpZ24nLCBhcy5jaGFyYWN0ZXIpIC0+IHNwX291dHB1dCRlZGdlc19kZgoKICAgIHRveV9waGVub3Njb3JlX291dHB1dDwtIHBoZW5vc2NvcmVfY29tcHV0YXRpb24ocHJvdGVpbnNfZGYgPSBzcF9vdXRwdXQkbm9kZXNfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lyZWRfcGhlbm90eXBlcyA9IGMoZGVzaXJlZF9waGVub3R5cGVzJHBoZW5vdHlwZXMsJ0FVVE9QSEFHWScpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaGVub19kaXN0YW5jZXNfdGFibGUgPSBwaGVub190YWJsZV9kaXN0YW5jZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwX2dyYXBoID0gc3Bfb3V0cHV0JGlncmFwaF9uZXR3b3JrLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNsb3NlbmVzcyBvZiBwcm90ZWlucyB0byBwaGVub3R5cGVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfbGVuZ3RoID0gNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdCA9ICdtZWFuJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgenNjb3JlX3RocmVzaG9sZCA9IC0xLjk2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGV4Y2x1ZGUgcmFuZG9tIHBoZW5vdHlwZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9yYW5kb20gPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdmFsdWVfdGhyZXNob2xkID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBvcHRpbWl6ZWQgbmV0d29yayAgc3BlY2lmaWNpdHkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX2Nhc2NhZGUgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub2RlX2lkeCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VfY2Fybml2YWxfYWN0aXZpdHkgPSBUUlVFKQoKICAgIHdyaXRlX3Jkcyh0b3lfcGhlbm9zY29yZV9vdXRwdXQsIHBhc3RlMChpbnB1dF9wYXRoLCAnL3BoZW5vc2NvcmUucmRzJykpCgoKICAgIHNvbHZlciA9ICdjcGxleCcKICAgIGNhcm5pdmFsX29wdGlvbnMgPC0gZGVmYXVsdF9DQVJOSVZBTF9vcHRpb25zKHNvbHZlcikKCiAgICBvcHQxIDwtIG9wdGltaXplX3BoZW5vX25ldHdvcmsoc3Bfb2JqZWN0ID0gdG95X3BoZW5vc2NvcmVfb3V0cHV0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gJ2h1bWFuJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaG9zcGhvX2RmID0gcGhvc3Bob19kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXJuaXZhbF9vcHRpb25zID0gY2Fybml2YWxfb3B0aW9ucywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoX2F0bGFzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aF9zaWYgPSBwYXN0ZTAoaW5wdXRfcGF0aCwgJy9waGVub19vcHQxLnNpZicpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfcmRzID0gcGFzdGUwKGlucHV0X3BhdGgsICcvcGhlbm9fb3B0MS5yZHMnKSkKCgoKICAgIG9wdGltaXplZF9zcF9vdXRwdXQgPC0gcmVhZFJEUyhwYXN0ZTAoaW5wdXRfcGF0aCwgJy9waGVub19vcHQxLnJkcycpKQoKICAgICMKICAgICMgIyBWSVNVQUxJWkFUSU9OIE9GIFRIRSBNT0RFTAogICAgIwogICAgZmluYWxfc3BfdmlzdWFsaXphdGlvbiA8LSBmb3JtYXRfZm9yX3Zpc3VhbGl6YXRpb24ob3B0aW1pemVkX3NwX291dHB1dCkKCiAgICBSQ3kzOjpjcmVhdGVOZXR3b3JrRnJvbUlncmFwaChpZ3JhcGg9ZmluYWxfc3BfdmlzdWFsaXphdGlvbiRpZ3JhcGhfbmV0d29yaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUwKGFuYWx5c2lzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb24gPSAnVG9fcGhlbm90eXBlcycpCiAgICAjIFNldCBpbiBDeXRvc2NhcGUgdGhlIFNpZ25hbGluZ1Byb2ZpbGVyIHN0eWxlIGF2YWlsYWJsZSBpbiBTaWduYWxpbmdQcm9maWxlciBSIHBhY2thZ2UKICAjICBkYXRhX3BhdGggPC0gc3lzdGVtLmZpbGUoImV4dGRhdGEiLCAiU1BfcGhlbm9fbGF5b3V0LnhtbCIsIHBhY2thZ2UgPSAiU2lnbmFsaW5nUHJvZmlsZXIiKQogICMgIFJDeTM6OmltcG9ydFZpc3VhbFN0eWxlcyhmaWxlbmFtZSA9IGRhdGFfcGF0aCkKICAgIFJDeTM6OnNldFZpc3VhbFN0eWxlKCdTUF9waGVub19sYXlvdXQnKQp9CgpgYGAKCiMgU2Vuc2l0aXZlIGNlbGxzIEltYXRpbmliIGNoYXJhY3Rlcml6YXRpb24KCiMjIEluZmVycmVkIHByb3RlaW5zIGNoYXJhY3Rlcml6YXRpb24KCldlIGZpcnN0IGtlZXAgb25seSBwcm90ZWlucyB0aGF0IGhhdmUgdGhlIHNhbWUgbW9kdWxhdGlvbiBpbiBLNTYyIGFuZCBMQU1BODQgY2VsbCBsaW5lLiBXZSB1c2UgdGhlICpwcm90ZW9zY29yZSogZm9yIHRyYW5zY3JpcHRpb24gZmFjdG9ycy4KCj4gU2NhdHRlcnBsb3Qgb2YgaW5mZXJyZWQgcHJvdGVpbnMKCmBgYHtyIGV2YWwgPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0KYWN0aXZpdHlfZGYgPC0gcmVhZF90c3YoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvZmluYWxfc2NvcmUudHN2Jywgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKYWN0aXZpdHlfZGYgJT4lIGZpbHRlcihtZiA9PSAnb3RoZXInKSAtPiB0b3BfdGFibGUKYWN0aXZpdHlfZGYgJT4lIGZpbHRlcihtZiAhPSAnb3RoZXInKSAtPiBib3R0b21fdGFibGUKcGxvdF90cmljayA8LSBiaW5kX3Jvd3ModG9wX3RhYmxlLGJvdHRvbV90YWJsZSkKCmNvbG9yX2xpc3QgPC0gbGlzdChraW4gPSAnI0Q0MTQ1QScsIHBob3MgPSAnIzAwOTI0NScsIG90aGVyID0gJyNCQTlCQzknLCB0ZiA9ICcjRjc5MzFFJykKCmdncGxvdChwbG90X3RyaWNrLCBhZXMoeCA9IGZpbmFsX3Njb3JlLks1NjIsIHkgPSBmaW5hbF9zY29yZS5MQU1BODQsIGxhYmVsID0gZ2VuZV9uYW1lKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gbWYpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGFiKCdBY3Rpdml0eSBtb2R1bGF0aW9uIEs1NjIgSW1hIHZzIEN0cmwnKSArCiAgeWxhYignQWN0aXZpdHkgbW9kdWxhdGlvbiBMQU1BODQgSW1hIHZzIEN0cmwnKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX2xpc3QpKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2dwdWJyOjpzdGF0X2NvcigpICsKICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJywgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpIAoKYGBgCioqRmlndXJlIDNBKiogUHJvdGVpbiBhY3Rpdml0eSBwcmVkaWN0aW9uIHJlc3VsdHMuIFNjYXR0ZXJwbG90cyBzaG93aW5nIHRoZSBjb21wYXJpc29uIGJldHdlZW4gcHJvdGVpbiBhY3Rpdml0eSBwcmVkaWN0ZWQgaW4gSzU2MiAoeC1heGlzKSBhbmQgTEFNQTg0ICh5LWF4aXMpIGRhdGFzZXRzLiBFYWNoIGRvdCByZXByZXNlbnRzIGEgcHJvdGVpbiwgYW5kIHRoZSBjb2xvciBpbmRpY2F0ZXMgdGhlIG1vbGVjdWxhciBmdW5jdGlvbjoga2luYXNlcyAocHVycGxlKSwgcGhvc3BoYXRhc2VzIChncmVlbiksIG90aGVycyAodmlvbGV0KSwgYW5kIHRyYW5zY3JpcHRpb24gZmFjdG9ycyAob3JhbmdlKS4gUiBpbmRpY2F0ZXMgUGVhcnNvbiBjb3JyZWxhdGlvbi4KCgojIyBOZXR3b3JrIGFuYWx5c2lzCgo+IE5vZGVzIHRhYmxlCgpgYGB7cn0KcGhlbm9zY29yZV9uZXR3b3JrIDwtIHJlYWRSRFMoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvcGhlbm9fb3B0MS5yZHMnKQpEVDo6ZGF0YXRhYmxlKHBoZW5vc2NvcmVfbmV0d29yayRub2Rlc19kZikKYGBgCgo+IEVkZ2VzIHRhYmxlCgpgYGB7cn0KcGhlbm9zY29yZV9uZXR3b3JrIDwtIHJlYWRSRFMoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvcGhlbm9fb3B0MS5yZHMnKQpEVDo6ZGF0YXRhYmxlKHBoZW5vc2NvcmVfbmV0d29yayRlZGdlc19kZikKd3JpdGVfdHN2KHBoZW5vc2NvcmVfbmV0d29yayRlZGdlc19kZiwgJy4uL3Jlc3VsdHMvaW1hX2N0cmwvZWRnZXNfdG9fcGhlbm90eXBlcy50c3YnKQpgYGAKCiMjIyMjIEJhcnBsb3Qgb2YgcmVzdWx0aW5nIHBoZW5vdHlwZXMKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NSB9CnBoZW5vc2NvcmVfcmVzdWx0IDwtIHJlYWRSRFMoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvcGhlbm9zY29yZS5yZHMnKQpwaGVub3Njb3JlX3Jlc3VsdCRiYXJwbG90CmBgYAoKKipGaWd1cmUgUzNGKiogQmFyIHBsb3Qgb2YgdGhlIHBoZW5vdHlwaWMgbW9kdWxhdGlvbiB1cG9uIGltYXRpbmliIHRyZWF0bWVudCBpbiBzZW5zaXRpdmUgY2VsbHMgaW5mZXJyZWQgYnkgU2lnbmFsaW5nUHJvZmlsZXIgMi4wLiAgQmx1ZSBhbmQgcmVkIGJhcnMgcmVwcmVzZW50IGluYWN0aXZlIGFuZCBhY3RpdmUgcGhlbm90eXBlcywgcmVzcGVjdGl2ZWx5LgoKIyMjIyBGdW5jdGlvbmFsIGNpcmN1aXRzIGZyb20gQkNSLUFCTDEgdG8gcGhlbm90eXBlcwoKV2UgZ2VuZXJhdGVkIGEgZnVuY3Rpb25hbCBjaXJjdWl0IG9mICozNyBub2RlcyBhbmQgODggZWRnZXMqIGxpbmtpbmcgaW5oaWJpdGVkIEJDUi1BQkwgdG8gcGhlbm90eXBlcy4KCmBgYHtyIGV2YWwgPSBGQUxTRX0KcGhlbm9zY29yZV9uZXR3b3JrIDwtIHJlYWRSRFMoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvcGhlbm9fb3B0MS5yZHMnKQpwaGVub3R5cGVzIDwtIGMoJ0FQT1BUT1NJUycsICdQUk9MSUZFUkFUSU9OJywgJ0cxX1NfVFJBTlNJVElPTicsICdETkFfUkVQQUlSJywgJ0NFTExfQ1lDTEVfQkxPQ0snLCAnQ0VMTF9DWUNMRV9FWElUJywgJ0ROQV9GUkFHTUVOVEFUSU9OJykKCnBoZW5vc2NvcmVfbmV0d29yayA8LSBmb3JtYXRfZm9yX3Zpc3VhbGl6YXRpb24ocGhlbm9zY29yZV9uZXR3b3JrKQoKayA9IDcKY2lyY3VpdCA8LSBwaGVub190b19zdGFydF9jaXJjdWl0KFNQX29iamVjdCA9IHBoZW5vc2NvcmVfbmV0d29yaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRfbm9kZXMgPSBjKCdCQ1JfQUJMJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBoZW5vdHlwZXMgPSBwaGVub3R5cGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRfdG9fdG9wID0gVFJVRSkKYGBgCgohWyoqRnVuY3Rpb25hbCBjaXJjdWl0KipdKC4vaW1nL0ltYV9DdHJsX2NpcmN1aXQucG5nKQoqKkZpZ3VyZSAzQioqIEZ1bmN0aW9uYWwgc3VibW9kZWwgZXh0cmFjdGVkIGZyb20gKlNpZ25hbGluZ1Byb2ZpbGVyKiAyLjAgb3V0cHV0IGxpbmtpbmcgQkNSLUFCTCB0byBjZWxsdWxhciBwaGVub3R5cGVzIG1vZHVsYXRlZCB1cG9uIGltYXRpbmliIHRyZWF0bWVudC4gSGlnaGxpZ2h0ZWQgcHJvdGVpbnMgYXJlIHZhbGlkYXRlZCBieSB3ZXN0ZXJuIGJsb3QgYW5hbHlzaXMuIAoKIyMgQ29tcGFyaXNvbiBiZXR3ZWVuIEs1NjIgYW5kIHBhdGllbnRzClRvIGNvbXBhcmUgcGF0aWVudHMgYW5kIGNlbGwgbGluZXMsIHdlIGNvbXB1dGVkIHRoZSBhY3Rpdml0eSBvZiB0cmFuc2NyaXB0aW9uIGZhY3RvcnMgZnJvbSB0cmFuc2NyaXB0b21pY3MgZGF0YSBvZiBwYXRpZW50cyBkb3dubG9hZGVkIGZyb20gR0VPIChkYXRhc2V0IG4uR1NFMjE2ODM3KQpgYGB7ciBldmFsID0gRkFMU0V9CiMgVHJhbnNmb3JtIFJOQXNlcSBkYXRhIGluIFNpZ25hbGluZ1Byb2ZpbGVyIGNvbXBsaWFudCBmb3JtYXQKdHJfZGZfcCA8LSByZWFkX3RzdignLi4vaW5wdXQvcGF0aWVudHNfbVJOQV9pbWFfY3RybC50c3YnLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoKdGZlYV9yZXMgPC0gcnVuX2Zvb3RwcmludF9iYXNlZF9hbmFseXNpcyhvbWljX2RhdGEgPSB0cl9kZl9wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmFseXNpcyA9ICd0ZmVhJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAnaHVtYW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdfbWluc2l6ZSA9IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsZWN0cmkgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBfc2lnbiA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoeXBlcmdlb21fY29yciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdPX2Fubm90YXRpb24gPSBUUlVFKQoKd3JpdGVfdHN2KHRmZWFfcmVzLCAnLi4vcmVzdWx0cy9pbWFfY3RybC9wYXRpZW50c190ZnMudHN2JykKYGBgCgpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0KIyBDb21wYXJlIHdpdGggazU2MiBURiBhY3Rpdml0eQp0ZmVhX3JlcyA8LSByZWFkX3RzdignLi4vcmVzdWx0cy9pbWFfY3RybC9wYXRpZW50c190ZnMudHN2Jywgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKCnRmc190YWJsZSA8LSByZWFkX3RzdignLi4vcmVzdWx0cy9pbWFfY3RybC9maW5hbF9zY29yZS50c3YnLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQp0ZnNfdGFibGUgJT4lIGZpbHRlcighaXMubmEoZmluYWxfc2NvcmUuSzU2MikpICU+JSBmaWx0ZXIobWYgPT0gJ3RmJyktPiB0ZnNfdGFibGVfazU2MgoKaW5uZXJfam9pbih0ZmVhX3JlcywgdGZzX3RhYmxlX2s1NjIsIGJ5ID0gJ2dlbmVfbmFtZScpIC0+IG1lcmdlZAoKIG1lcmdlZF9URnMgPC0gbWVyZ2VkICU+JSBkcGx5cjo6c2VsZWN0KGdlbmVfbmFtZSwgd2VpZ2h0ZWRORVMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaW5hbF9zY29yZSA9IGZpbmFsX3Njb3JlLks1NjIpCiAKbWVyZ2VkX1RGcyAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCdnZW5lX25hbWUnKSAtPiBtZXJnZWRfbQptZXJnZWRfbVtpcy5uYShtZXJnZWRfbSldIDwtIDAKCm1lcmdlZF9tICU+JSByb3duYW1lc190b19jb2x1bW4oJ2dlbmVfbmFtZScpIC0+IG1lcmdlZF9URnMKICAgIApnZ3Bsb3QobWVyZ2VkX1RGcywgYWVzKHggPSB3ZWlnaHRlZE5FUywgeSA9IGZpbmFsX3Njb3JlLCBsYWJlbCA9IGdlbmVfbmFtZSkpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgICAgIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgpICsKICAgICAgeGxhYignUGF0aWVudHMgaW5mZXJyZWQgYWN0aXZpdHkgbW9kdWxhdGlvbicpICsKICAgICAgZ2dwdWJyOjpzdGF0X2NvcigpICsKICAgICAgdGhlbWVfY2xhc3NpYygpIApgYGAKCioqRmlndXJlIDJEKiogU2NhdHRlcnBsb3Qgb2YgdHJhbnNjcmlwdGlvbiBmYWN0b3Jz4oCZIGluZmVycmVkIGFjdGl2aXR5IHdpdGggU2lnbmFsbmlnUHJvZmlsZXIgMi4wIGluIHBhdGllbnRzIHNhbXBsZXMgZnJvbSBHRU8gZGF0YXNldCBuLiBHU0UyMTY4MzcgKHgtYXhpcykgYW5kIEs1NjIgY2VsbCBsaW5lICh5LWF4aXMpIHVwb24gaW1hdGluaWIgZXhwb3N1cmUuIFIgcmVwcmVzZW50cyBQZWFyc29uIGNvcnJlbGF0aW9uLiAKCiMgUmVzaXN0YW50IGNlbGxzIHZzIFNlbnNpdGl2ZSBjZWxscyBjaGFyYWN0ZXJpemF0aW9uCgojIyBJbmZlcnJlZCBwcm90ZWlucyBjaGFyYWN0ZXJpemF0aW9uCgpgYGB7cn0KcHJvdGVpbl9kZiA8LSByZWFkX3RzdignLi4vcmVzdWx0cy9yZXNfc2Vucy9maW5hbF9zY29yZS50c3YnLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpEVDo6ZGF0YXRhYmxlKHByb3RlaW5fZGYpCmBgYAoKIyMjIyBDb21wYXJpc29uIGJldHdlZW4gUmVzIHZzIFNlbnMgYW5kIEltYSB2cyBDdHJsCgpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0KCnByb3RlaW5fZGZfcnMgPC0gcmVhZF90c3YoJy4uL3Jlc3VsdHMvcmVzX3NlbnMvZmluYWxfc2NvcmUudHN2Jywgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKcHJvdGVpbnNfZGZfaW1hX2N0cmwgPC0gcmVhZF90c3YoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvZmluYWxfc2NvcmUudHN2Jywgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lIAogIGZpbHRlcighaXMubmEoZmluYWxfc2NvcmUuSzU2MikpICU+JQogIGRwbHlyOjpzZWxlY3QoVU5JUFJPVCA9IFVOSVBST1QuSzU2MiwgZ2VuZV9uYW1lLCBtZiwgbWV0aG9kID0gbWV0aG9kLks1NjIsIGZpbmFsX3Njb3JlID0gZmluYWxfc2NvcmUuSzU2MikKCmZ1bGxfam9pbihwcm90ZWluc19kZl9pbWFfY3RybCwgcHJvdGVpbl9kZl9ycywgYnkgPSBjKCdnZW5lX25hbWUnLCAnbWYnKSwgc3VmZml4ID0gYygnLmltYScsICcucmVzJykpIC0+IGFsbF9wcm90ZWluc19kZgoKI3dyaXRlX3RzdihhbGxfcHJvdGVpbnNfZGYsICcuLi9yZXN1bHRfY2xlYW5fYmYvbWF0Y2hlZF9pbWFfcmVzX2N0cmwudHN2JykKCmFsbF9wcm90ZWluc19kZl9raW4gPC0gYWxsX3Byb3RlaW5zX2RmICU+JSBmaWx0ZXIobWYgPT0gJ2tpbicgfCBtZiA9PSAncGhvcycpCgpjb2xvcl9saXN0IDwtIGxpc3Qoa2luID0gJyNENDE0NUEnLCBwaG9zID0gJyMwMDkyNDUnLCBvdGhlciA9ICcjQkE5QkM5JywgdGYgPSAnI0Y3OTMxRScpCgpnZ3Bsb3QoYWxsX3Byb3RlaW5zX2RmX2tpbiwgYWVzKHggPSBmaW5hbF9zY29yZS5pbWEsIHkgPSBmaW5hbF9zY29yZS5yZXMsIGxhYmVsID0gZ2VuZV9uYW1lKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gbWYpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGFiKCdBY3Rpdml0eSBtb2R1bGF0aW9uIEs1NjIgSW1hIHZzIEN0cmwnKSArCiAgeWxhYignQWN0aXZpdHkgbW9kdWxhdGlvbiBSZXMgdnMgQ3RybCcpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfbGlzdCkrCiAgdGhlbWVfY2xhc3NpYygpICsKICBnZ3B1YnI6OnN0YXRfY29yKCkgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChzaXplID0gMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLCB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgCgpgYGAKKipGaWd1cmUgNEUqKiAgU2NhdHRlcnBsb3RzIHNob3dpbmcgdGhlIGNvbXBhcmlzb24gYmV0d2VlbiBraW5hc2VzIGFjdGl2aXR5IHByZWRpY3RlZCBpbiBTZW5zaXRpdmUgKHgtYXhpcykgYW5kIFJlc2lzdGFudCAoeS1heGlzKSB2cyBDb250cm9sIGRhdGFzZXRzIGZvciBraW5hc2VzIGFuZCBwaG9zcGhhdGFzZXMuIEVhY2ggZG90IHJlcHJlc2VudHMgYSBwcm90ZWluLiBSIGluZGljYXRlcyBQZWFyc29uIGNvcnJlbGF0aW9uLgoKCiMjIEJDUi1BQkwgZGVwZW5kZW50IHNpZ25hbGluZyBuZXR3b3JrCmBgYHtyIGV2YWwgPSBGQUxTRSwgIHdhcm5pbmcgPSBGQUxTRX0KaW1hX2N0cmwgPC0gcmVhZFJEUygnLi4vcmVzdWx0cy9pbWFfY3RybC9waGVub19vcHQxLnJkcycpCnJlc19zZW5zIDwtIHJlYWRSRFMoJy4uL3Jlc3VsdHMvcmVzX3NlbnMvcGhlbm9zY29yZS5yZHMnKQoKaW1hX2N0cmxfcHJvdCA8LSBpbWFfY3RybCRub2Rlc19kZgpyZXNfc2Vuc19wcm90IDwtIHJlc19zZW5zJHNwX29iamVjdF9waGVub3R5cGVzJG5vZGVzX2RmCgppbm5lcl9qb2luKGltYV9jdHJsX3Byb3QsIHJlc19zZW5zX3Byb3QsIGJ5ID0gYygnZ2VuZV9uYW1lJyksIHN1ZmZpeCA9IGMoJy5pbWEnLCAnLnJlcycpKSAtPiBqb2luZWRfcHJvdHMKam9pbmVkX3Byb3RzICU+JSBmaWx0ZXIoY2Fybml2YWxfYWN0aXZpdHkucmVzICogY2Fybml2YWxfYWN0aXZpdHkuaW1hID4gMCkgLT4gc2FtZV9yZWd1bGF0aW9uCgprMSA9IDUKdGFyZ2V0cyA8LSBzYW1lX3JlZ3VsYXRpb24kZ2VuZV9uYW1lCgpyZXNfbmV0d29ya19vcHQgPC0gcmVzX3NlbnMkc3Bfb2JqZWN0X3BoZW5vdHlwZXMKCnBoZW5vX3RvX3N0YXJ0X2NpcmN1aXQoU1Bfb2JqZWN0ID0gcmVzX25ldHdvcmtfb3B0LAogICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0X25vZGVzID0gYygnQkNSX0FCTCcpLAogICAgICAgICAgICAgICAgICAgICAgIHBoZW5vdHlwZXMgPSB0YXJnZXRzLCAjYyhvcHBvc2l0ZXMkZ2VuZV9uYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICBrID0gazEpIC0+IGNpcmN1aXRfcmVzCgphc19kYXRhX2ZyYW1lKHggPSBjaXJjdWl0X3Jlcywgd2hhdCA9IGMoJ3ZlcnRpY2VzJykpIC0+IHByb3RlaW5zX3Jlc19jaXJjdWl0CgprMiA9IDEKcGhlbm9fdG9fc3RhcnRfY2lyY3VpdChTUF9vYmplY3QgPSByZXNfbmV0d29ya19vcHQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRfbm9kZXMgPSAgcHJvdGVpbnNfcmVzX2NpcmN1aXQkbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICBwaGVub3R5cGVzID0gYygnUFJPTElGRVJBVElPTicsICdBUE9QVE9TSVMnKSwgI2Mob3Bwb3NpdGVzJGdlbmVfbmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgayA9IGsyKSAtPiBjaXJjdWl0X3Jlc19waGVubwoKIyBDcmVhdGUgdGhlIHVuaW9uCnBoZW5vX2NpcmN1aXRfcHJvdGVpbnMgPC0gYXNfZGF0YV9mcmFtZSh4ID0gY2lyY3VpdF9yZXNfcGhlbm8sIHdoYXQgPSBjKCd2ZXJ0aWNlcycpKQpzaWdfY2lyY3VpdF9wcm90ZWlucyA8LSBhc19kYXRhX2ZyYW1lKHggPSBjaXJjdWl0X3Jlcywgd2hhdCA9IGMoJ3ZlcnRpY2VzJykpCmJpbmRfcm93cyhwaGVub19jaXJjdWl0X3Byb3RlaW5zLCBzaWdfY2lyY3VpdF9wcm90ZWlucykgJT4lIGRpc3RpbmN0KCkgLT4gdW5pb25fZGZfbm9kZXMKCnBoZW5vX2NpcmN1aXRfZWRnZXM8LSBhc19kYXRhX2ZyYW1lKHggPSBjaXJjdWl0X3Jlc19waGVubywgd2hhdCA9IGMoJ2VkZ2VzJykpCnNpZ19jaXJjdWl0X2VkZ2VzIDwtIGFzX2RhdGFfZnJhbWUoeCA9IGNpcmN1aXRfcmVzLCB3aGF0ID0gYygnZWRnZXMnKSkKYmluZF9yb3dzKHBoZW5vX2NpcmN1aXRfZWRnZXMsIHNpZ19jaXJjdWl0X2VkZ2VzKSAlPiUgZGlzdGluY3QoKSAtPiB1bmlvbl9kZl9lZGdlcwoKZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGQgPSB1bmlvbl9kZl9lZGdlcywgdmVydGljZXMgPSB1bmlvbl9kZl9ub2RlcykgLT4gZmluYWxfZ3JhcGgKCiN3cml0ZV9yZHMoZmluYWxfZ3JhcGgsICcuLi9yZXN1bHRzL3Jlc19zZW5zL2Jjcl9kZXBlbmRlbnRfbmV0d29yay5yZHMnKQoKUkN5Mzo6Y3JlYXRlTmV0d29ya0Zyb21JZ3JhcGgoaWdyYXBoPWZpbmFsX2dyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMCgnazEgPSAnLCBrMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb24gPSAnQkNSLUFCTCBkZXBlbmRlbnQgbmV0d29yaycpCgojZGF0YV9wYXRoIDwtIHN5c3RlbS5maWxlKCJleHRkYXRhIiwgIlNQX3BoZW5vX2xheW91dC54bWwiLCBwYWNrYWdlID0gIlNpZ25hbGluZ1Byb2ZpbGVyIikKI1JDeTM6OmltcG9ydFZpc3VhbFN0eWxlcyhmaWxlbmFtZSA9IGRhdGFfcGF0aCkKUkN5Mzo6c2V0VmlzdWFsU3R5bGUoJ1NQX3BoZW5vX2xheW91dCcpCgpgYGAKCiMjIyMjIFZpc3VhbGl6YXRpb24gb2YgYW50aS1zdXJ2aXZhbCBheGVzIGNvbnNlcnZlZCBpbiByZXNpc3RhbnQgY2VsbHMKYGBge3IgZXZhbCA9IEZBTFNFfQpiY3JfYWJsX2RlcGVuZGVudCA8LSByZWFkUkRTKCcuLi9yZXN1bHRzL3Jlc19zZW5zL2RydWdnYWJpbGl0eV9zY29yZS9iY3JfYWJsX2RlcGVuZGVudF9yZXMucmRzJykKbm9kZXNfYmNyX2RlcF9uZXR3b3JrIDwtIGFzX2RhdGFfZnJhbWUoYmNyX2FibF9pbmRlcGVuZGVudCwgd2hhdCA9ICd2ZXJ0aWNlcycpCmVkZ2VzX2Jjcl9kZXBfbmV0d29yayA8LSBhc19kYXRhX2ZyYW1lKGJjcl9hYmxfaW5kZXBlbmRlbnQsIHdoYXQgPSAnZWRnZXMnKQoKIyBJc29sYXRlIHByb3RlaW5zIGFuZCBwaGVub3R5cGVzCnByb3RlaW5zX2RmIDwtIG5vZGVzX2Jjcl9kZXBfbmV0d29yayAlPiUgI2RwbHlyOjpmaWx0ZXIobmFtZSAlaW4lIGRydWdnYWJpbGl0eV9yZXN1bHRfc3ViJGdlbmVfbmFtZSkgJT4lCiAgZHBseXI6OnNlbGVjdChnZW5lX25hbWUgPSBuYW1lLCBVTklQUk9ULCBmaW5hbF9zY29yZSA9IGNhcm5pdmFsX2FjdGl2aXR5LCBtZXRob2QsIG1mKSAlPiUKICBmaWx0ZXIoIWdlbmVfbmFtZSAlaW4lIGMoJ0FQT1BUT1NJUycsICdQUk9MSUZFUkFUSU9OJykpCgp0YXJnZXRfZGYgPC0gbm9kZXNfYmNyX2RlcF9uZXR3b3JrICU+JSBkcGx5cjo6ZmlsdGVyKG5hbWUgJWluJSBjKCdBUE9QVE9TSVMnLCAnUFJPTElGRVJBVElPTicpKQp0YXJnZXRfZGYkY2Fybml2YWxfYWN0aXZpdHkgPC0gYygxMDAsIC0xMDApCnRhcmdldF9kZiA8LSB0YXJnZXRfZGYgJT4lCiAgZHBseXI6OnNlbGVjdChnZW5lX25hbWUgPSBuYW1lLCBVTklQUk9ULCBmaW5hbF9zY29yZSA9IGNhcm5pdmFsX2FjdGl2aXR5LCBtZXRob2QsIG1mKQoKIyBUcmFuc2Zvcm0gdGhlIG9wdGltaXplZCBuZXR3b3JrIGVkZ2VzIGluIFNJRiBmb3JtYXQKcGhlbm9fbmFpdmVfZGYgPC0gZWRnZXNfYmNyX2RlcF9uZXR3b3JrICU+JSBkcGx5cjo6c2VsZWN0KHNvdXJjZSA9IGZyb20sIGludGVyYWN0aW9uID0gc2lnbiwgdGFyZ2V0ID0gdG8pCgpzb2x2ZXIgPSAnY3BsZXgnCmNhcm5pdmFsX29wdGlvbnMgPSBkZWZhdWx0X0NBUk5JVkFMX29wdGlvbnMoc29sdmVyKQpvdXRwdXQxIDwtIHJ1bl9jYXJuaXZhbF9hbmRfY3JlYXRlX2dyYXBoKHNvdXJjZV9kZiA9IHByb3RlaW5zX2RmICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRfZGYgPSB0YXJnZXRfZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFpdmVfbmV0d29yayA9IHVuaXF1ZShwaGVub19uYWl2ZV9kZiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdGVpbnNfZGYgPSBub2Rlc19iY3JfZGVwX25ldHdvcmsgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGdlbmVfbmFtZSA9IG5hbWUsIFVOSVBST1QsIGZpbmFsX3Njb3JlLCBtZXRob2QsIG1mKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICdodW1hbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2Fybml2YWxfb3B0aW9ucyA9IGNhcm5pdmFsX29wdGlvbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2l0aF9hdGxhcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfc2lmID0gJy4uL3Jlc3VsdHMvcmVzX3NlbnMvZGVwX2NpcmN1aXRfb3B0aW1pemVkLnNpZicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aF9yZHMgPSAnLi4vcmVzdWx0cy9yZXNfc2Vucy9kZXBfY2lyY3VpdF9vcHRpbWl6ZWQucmRzJykKCiMgTWFwIG9taWNzIG9uIHRoZSBvcHRpbWl6ZWQgbW9kZWwKcGhvc3Bob19kZiA8LSByZWFkX3RzdignLi4vaW5wdXQvcGhvc3Bob19LNTYyX3Jlc19zZW5zX1NQLnRzdicpCgpzcF9vdXRwdXRfZGYgPC0gZXhwYW5kX2FuZF9tYXBfZWRnZXMob3B0aW1pemVkX29iamVjdCA9IG91dHB1dDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICdodW1hbicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaG9zcGhvX2RmID0gcGhvc3Bob19kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoX2F0bGFzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoX3NpZiA9ICcuLi9yZXN1bHRzL3Jlc19zZW5zL2luZF9jaXJjdWl0X29wdGltaXplZF92YWxpZGF0ZWQuc2lmJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfcmRzID0gJy4uL3Jlc3VsdHMvcmVzX3NlbnMvaW5kX2NpcmN1aXRfb3B0aW1pemVkX29wdGltaXplZF92YWxpZGF0ZWQucmRzJykKCnNwX291dHB1dF9kZiRub2Rlc19kZiA8LSBzcF9vdXRwdXRfZGYkbm9kZXNfZGYgJT4lCiAgbXV0YXRlKGdvbGRfc3RhbmRhcmQgPSBpZmVsc2UoZ2VuZV9uYW1lICVpbiUgc2FtZV9yZWd1bGF0aW9uJGdlbmVfbmFtZSwgJ1knLCAnTicpKQoKc3Bfb3V0cHV0X2RmJGlncmFwaF9uZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkID0gc3Bfb3V0cHV0X2RmJGVkZ2VzX2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2VzID0gc3Bfb3V0cHV0X2RmJG5vZGVzX2RmKQoKZmluYWxfc3BfdmlzdWFsaXphdGlvbiA8LSBmb3JtYXRfZm9yX3Zpc3VhbGl6YXRpb24oc3Bfb3V0cHV0X2RmKQoKUkN5Mzo6Y3JlYXRlTmV0d29ya0Zyb21JZ3JhcGgoaWdyYXBoPXNwX291dHB1dF9kZiRpZ3JhcGhfbmV0d29yaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSBwYXN0ZTAoJ0JDUl9BQkwgZGVwZW5kZW50IG5ldHdvcmsgb3B0aW1pemVkJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICN0aXRsZSA9IHBhc3RlMCgnQkNSX0FCTCBpbmRlcGVuZGVudCBuZXR3b3JrIG9wdGltaXplZCcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsZWN0aW9uID0gJ0JDUl9BQkwgaW5kZXBlbmRlbnQnKQojU2V0IGluIEN5dG9zY2FwZSB0aGUgU2lnbmFsaW5nUHJvZmlsZXIgc3R5bGUgYXZhaWxhYmxlIGluIFNpZ25hbGluZ1Byb2ZpbGVyIFIgcGFja2FnZQojZGF0YV9wYXRoIDwtIHN5c3RlbS5maWxlKCJleHRkYXRhIiwgIlNQX3BoZW5vX2xheW91dC54bWwiLCBwYWNrYWdlID0gIlNpZ25hbGluZ1Byb2ZpbGVyIikKI1JDeTM6OmltcG9ydFZpc3VhbFN0eWxlcyhmaWxlbmFtZSA9IGRhdGFfcGF0aCkKUkN5Mzo6c2V0VmlzdWFsU3R5bGUoJ1NQX3BoZW5vX2xheW91dCcpCmBgYAohWyoqQkNSLUFCTCBkZXBlbmRlbnQgc2lnbmFsaW5nIGF4ZXMgaW4gSzU2Mi1SKipdKC4vaW1nL0JDUl9BQkxfZGVwZW5kZW50LnBuZykKCiMjIEJDUi1BQkwgaW5kZXBlbmRlbnQgc2lnbmFsaW5nIG5ldHdvcmsKCiMjIyMgSWRlbnRpZmljYXRpb24gb2YgcmVjZXB0b3JzIG9wcG9zaXRlbHkgbW9kdWxhdGVkIGluIEs1NjItUiBhbmQgc2Vuc2l0aXZlIGNlbGxzCldlIGlkZW50aWZpZWQgMjMgYWx0ZXJuYXRpdmUgcmVjZXB0b3JzIHRoYXQgYXJlIHJlc2lzdGFudCBjZWxscy1zcGVjaWZpYyBvciBoYXZlIG9wcG9zaXRlIG1vZHVsYXRpb24gYmV0d2VlbiB0aGUgdHdvIGNlbGwgbGluZXMuCgpgYGB7ciBldmFsID0gRkFMU0V9CmltYV9jdHJsIDwtIHJlYWRSRFMoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvcGhlbm9fb3B0MS5yZHMnKQpyZXNfc2VucyA8LSByZWFkUkRTKCcuLi9yZXN1bHRzL3Jlc19zZW5zL3BoZW5vc2NvcmUucmRzJykKCiMgQW5ub3RhdGUgd2l0aCB0aGUgcHJvdGVpbiBuYW1lIHRvIGxvb2sgZm9yIHJlY2VwdG9yIHdvcmsKYmlvbWFydHI6OmdldE1hcnRzKCkKZ2VuZV9zZXQgPC0gb3Bwb3NpdGVzX2luX25ldHdvcmtzJGdlbmVfbmFtZQoKcmVzdWx0X0JNIDwtIGJpb21hcnRyOjpiaW9tYXJ0KCBnZW5lcyAgICAgID0gdW5pcXVlKGdlbmVfc2V0KSwgIyBnZW5lcyB3ZXJlIHJldHJpZXZlZCB1c2luZyBiaW9tYXJ0cjo6Z2V0R2Vub21lKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJ0ICAgICAgID0gIkVOU0VNQkxfTUFSVF9FTlNFTUJMIiwgIyBtYXJ0cyB3ZXJlIHNlbGVjdGVkIHdpdGggYmlvbWFydHI6OmdldE1hcnRzKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhc2V0ICAgID0gImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIsICMgZGF0YXNldHMgd2VyZSBzZWxlY3RlZCB3aXRoIGJpb21hcnRyOjpnZXREYXRhc2V0cygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXR0cmlidXRlcyA9IGMoInVuaXByb3Rzd2lzc3Byb3QiLCAiZGVzY3JpcHRpb24iKSwgIyBhdHRyaWJ1dGVzIHdlcmUgc2VsZWN0ZWQgd2l0aCBiaW9tYXJ0cjo6Z2V0QXR0cmlidXRlcygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVycyAgICA9ICJoZ25jX3N5bWJvbCIpICMgc3BlY2lmeSB3aGF0IElEIHR5cGUgd2FzIHN0b3JlZCBpbiB0aGUgZmFzdGEgZmlsZSByZXRyaWV2ZWQgd2l0aCBiaW9tYXJ0cjo6Z2V0R2Vub21lKCkKCnJlc3VsdF9CTSAgJT4lIGZpbHRlcih1bmlwcm90c3dpc3Nwcm90ICE9ICcnKSAtPiByZXN1bHRfQk1fY2xlYW4KcmVzdWx0X0JNX2NsZWFuICU+JSBmaWx0ZXIoZ3JlcGwoJ3JlY2VwdG9yJywgZGVzY3JpcHRpb24pKSAgLT4gcmVjZXB0b3JzX2xpc3QKCgpsZWZ0X2pvaW4ob3Bwb3NpdGVzX2luX25ldHdvcmtzLCByZXN1bHRfQk1fY2xlYW4sIGJ5ID0gYygnZ2VuZV9uYW1lJyA9ICdoZ25jX3N5bWJvbCcpKSAtPiBvcHBvc2l0ZXNfaW5fbmV0d29ya3NfYW5ubwpvcHBvc2l0ZXNfaW5fbmV0d29ya3NfYW5ubyAlPiUgbXV0YXRlKHJlY2VwdG9yID0gaWZlbHNlKGdlbmVfbmFtZSAlaW4lIHJlY2VwdG9yc19saXN0JGhnbmNfc3ltYm9sLCAneScsIE5BKSkgLT4gb3Bwb3NpdGVzX2luX25ldHdvcmtzX2Fubm8KCndyaXRlX3RzdihvcHBvc2l0ZXNfaW5fbmV0d29ya3NfYW5ubywgJy4uL3Jlc3VsdHMvcmVzX3NlbnMvYWN0aXZhdGVkX3Byb3RlaW5zX25ldHdvcmtfbmV3LnRzdicpCmBgYAoKYGBge3Igd2FybmluZyA9IEZBTFNFLCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTN9Cm9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vIDwtIHJlYWRfdHN2KCAnLi4vcmVzdWx0cy9yZXNfc2Vucy9hY3RpdmF0ZWRfcHJvdGVpbnNfbmV0d29ya19uZXcudHN2Jywgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKb3Bwb3NpdGVzX2luX25ldHdvcmtzX2Fubm8gJT4lIGZpbHRlcihyZWNlcHRvciA9PSAneScpIC0+IG9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vX3JlY2VwdHIKCmhlYXRtYXBfbWF0cml4IDwtIG9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vX3JlY2VwdHIgJT4lIGRwbHlyOjpzZWxlY3QoZ2VuZV9uYW1lLCBjYXJuaXZhbF9hY3Rpdml0eS5yZXMsIGNhcm5pdmFsX2FjdGl2aXR5LnNlbnMpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygnZ2VuZV9uYW1lJykKaGVhdG1hcF9hbm5vIDwtIG9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vX3JlY2VwdHIgJT4lIGRwbHlyOjpzZWxlY3QoZ2VuZV9uYW1lLCBtZXRob2QucmVzLCBtZXRob2Quc2VucykgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCdnZW5lX25hbWUnKQoKcGFsZXR0ZUxlbmd0aCA8LTEwMDAKUmRCdSA8LSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwobiA9IDExLCAnUmRCdScpCm15Q29sb3IgPC0gY29sb3JSYW1wUGFsZXR0ZShjKFJkQnVbMTBdLCAid2hpdGUiLCBSZEJ1WzJdKSkocGFsZXR0ZUxlbmd0aCkKCm15QnJlYWtzIDwtIGMoc2VxKC0xMDAsIDAsIGxlbmd0aC5vdXQ9Y2VpbGluZyhwYWxldHRlTGVuZ3RoLzIpICsxKSwKICAgICAgICAgICAgICBzZXEoMCwgMTAwLCBsZW5ndGgub3V0PWZsb29yKHBhbGV0dGVMZW5ndGgvMikpKQoKcCA8LSBwaGVhdG1hcDo6cGhlYXRtYXAodChhcy5tYXRyaXgoaGVhdG1hcF9tYXRyaXgpKSwKICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBteUNvbG9yLAogICAgICAgICAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgICAgICBjZWxsd2lkdGggPSA4LAogICAgICAgICAgICAgICAgICAgICAgICBjZWxsaGVpZ2h0ID0gOCwKICAgICAgICAgICAgICAgICAgICAgICAgZm9udHNpemUgPSA4LAogICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB1bmlxdWUobXlCcmVha3MpLAogICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGhlYXRtYXBfYW5ubywKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRyb3BfbGVnZW5kcyA9IFRSVUUpCmBgYAoKKipGaWd1cmUgUzZCKiogSGVhdG1hcCByZXBvcnRpbmcgZm9yIEs1NjItUiBhbmQgSzU2MiB0aGUgYWN0aXZpdHkgb2YgcmVjZXB0b3JhIGluIFNpZ25hbGluZ1Byb2ZpbGVyIDIuMCBnZW5lcmF0ZWQgbmV0d29ya3MuIAoKIyMjIyBCdWlsZCBCQ1ItQUJMIGluZGVwZW5kZW50IHNpZ25hbGluZyBuZXR3b3JrIGZyb20gYWx0ZXJuYXRpdmUgcmVjZXB0b3JzIAoKVGhlc2UgcmVjZXB0b3JzIHdlcmUgc2VsZWN0ZWQgYXMgc3RhcnRpbmcgcG9pbnRzIGZvciBmdW5jdGlvbmFsIGNpcmN1aXRzIG9mIG1heGltdW0gcGF0aCBsZW5ndGggb2YgNi4KYGBge3IgZXZhbCA9IEZBTFNFfQpsaWJyYXJ5KGlncmFwaCkKIyBSZWFkIHNlbnNpdGl2ZSBhbmQgcmVzaXN0YW50IGNlbGxzIG5ldHdvcmtzCmltYV9jdHJsIDwtIHJlYWRSRFMoJy4uL3Jlc3VsdHMvaW1hX2N0cmwvcGhlbm9fb3B0MS5yZHMnKQpyZXNfc2VucyA8LSByZWFkUkRTKCcuLi9yZXN1bHRzL3Jlc19zZW5zL3BoZW5vc2NvcmUucmRzJykKCiMgUmVhZCByZWNlcHRvcnMgd2l0aCBvcHBvc2l0ZSBhY3Rpdml0eSB0YWJsZQpvcHBvc2l0ZXNfaW5fbmV0d29ya3NfYW5ubyA8LSByZWFkX3RzdiggJy4uL3Jlc3VsdHMvcmVzX3NlbnMvYWN0aXZhdGVkX3Byb3RlaW5zX25ldHdvcmtfbmV3LnRzdicsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpCm9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vICU+JSBmaWx0ZXIocmVjZXB0b3IgPT0gJ3knKSAtPiBvcHBvc2l0ZXNfaW5fbmV0d29ya3NfYW5ub19yZWNlcHRyCm9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vICU+JSBmaWx0ZXIoaXMubmEocmVjZXB0b3IpKSAtPiBvcHBvc2l0ZXNfaW5fbmV0d29ya3NfYW5ub19vdGhlcnMKCiMgQ2hhbmdlIHZhcmlhYmxlIG5hbWVzCnJlc19uZXR3b3JrX29wdCA8LSByZXNfc2VucyRzcF9vYmplY3RfcGhlbm90eXBlcwpyZXNfbmV0d29ya19vcHQgPC0gZm9ybWF0X2Zvcl92aXN1YWxpemF0aW9uKHJlc19uZXR3b3JrX29wdCkKcmVzX25ldHdvcmtfb3B0JG5vZGVzX2RmIDwtIHJlc19uZXR3b3JrX29wdCRub2Rlc19kZiAlPiUKICBtdXRhdGUoZ29sZF9zdGFuZGFyZCA9IGlmZWxzZShnZW5lX25hbWUgJWluJQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3Bwb3NpdGVzX2luX25ldHdvcmtzX2Fubm8kZ2VuZV9uYW1lLCAnWScsIE5BKSkKcmVzX25ldHdvcmtfb3B0JGlncmFwaF9uZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkID0gcmVzX25ldHdvcmtfb3B0JGVkZ2VzX2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2VzID0gcmVzX25ldHdvcmtfb3B0JG5vZGVzX2RmKQoKc2Vuc19uZXR3b3JrX29wdCA8LSBpbWFfY3RybApzZW5zX25ldHdvcmtfb3B0JGlncmFwaF9uZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkID0gc2Vuc19uZXR3b3JrX29wdCRlZGdlc19kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVydGljZXMgPSBzZW5zX25ldHdvcmtfb3B0JG5vZGVzX2RmKQpzZW5zX25ldHdvcmtfb3B0IDwtIGZvcm1hdF9mb3JfdmlzdWFsaXphdGlvbihzZW5zX25ldHdvcmtfb3B0KQoKIyBJc29sYXRlIG9wcG9zaXRlIHByb3RlaW5zCm9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vX290aGVycyAlPiUgZmlsdGVyKG1mLnJlcyAhPSAncGhlbm90eXBlJykgLT4gb3Bwb3NpdGVzX2luX25ldHdvcmtzX2Fubm9fb3RoZXJzX25ldwoKCiMgQ3JlYXRlIGNpcmN1aXQKazEgPSA1Cgp0YXJnZXRzIDwtIG9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vX290aGVyc19uZXckZ2VuZV9uYW1lW29wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vX290aGVyc19uZXckZ2VuZV9uYW1lICVpbiUgcmVzX25ldHdvcmtfb3B0JG5vZGVzX2RmJGdlbmVfbmFtZV0KCnBoZW5vX3RvX3N0YXJ0X2NpcmN1aXQoU1Bfb2JqZWN0ID0gcmVzX25ldHdvcmtfb3B0LAogICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0X25vZGVzID0gYygnQkNSX0FCTCcsIG9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vX3JlY2VwdHIkZ2VuZV9uYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICBwaGVub3R5cGVzID0gdGFyZ2V0cywgI2Mob3Bwb3NpdGVzJGdlbmVfbmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgayA9IGsxKSAtPiBjaXJjdWl0X3JlcwoKUkN5Mzo6Y3JlYXRlTmV0d29ya0Zyb21JZ3JhcGgoaWdyYXBoPWNpcmN1aXRfcmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMCgnb3Bwb3NpdGVzIGs9JywgaywgJyBORVdORVcnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbGVjdGlvbiA9ICdSZXMgbmV3IHJlY2VwdG9yIHVwIGFuZCBkb3duJykKClJDeTM6OnNldFZpc3VhbFN0eWxlKCdTUF9waGVub19sYXlvdXQnKQoKYXNfZGF0YV9mcmFtZSh4ID0gY2lyY3VpdF9yZXMsIHdoYXQgPSBjKCd2ZXJ0aWNlcycpKSAtPiBwcm90ZWluc19yZXNfY2lyY3VpdApwcm90ZWluc19yZXNfY2lyY3VpdCAlPiUgZmlsdGVyKGdvbGRfc3RhbmRhcmQgPT0gJ1knKSAtPiBwcm90ZWluc19yZXNfY2lyY3VpdF9HCmsyID0gMQoKcGhlbm9fdG9fc3RhcnRfY2lyY3VpdChTUF9vYmplY3QgPSByZXNfbmV0d29ya19vcHQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRfbm9kZXMgPSAgcHJvdGVpbnNfcmVzX2NpcmN1aXRfRyRuYW1lLAogICAgICAgICAgICAgICAgICAgICAgIHBoZW5vdHlwZXMgPSBjKCdQUk9MSUZFUkFUSU9OJywgJ0FQT1BUT1NJUycpLCAjYyhvcHBvc2l0ZXMkZ2VuZV9uYW1lKSwKICAgICAgICAgICAgICAgICAgICAgICBrID0gazIpIC0+IGNpcmN1aXRfcmVzX3BoZW5vCgojIENyZWF0ZSB0aGUgdW5pb24KcGhlbm9fY2lyY3VpdF9wcm90ZWlucyA8LSBhc19kYXRhX2ZyYW1lKHggPSBjaXJjdWl0X3Jlc19waGVubywgd2hhdCA9IGMoJ3ZlcnRpY2VzJykpCnNpZ19jaXJjdWl0X3Byb3RlaW5zIDwtIGFzX2RhdGFfZnJhbWUoeCA9IGNpcmN1aXRfcmVzLCB3aGF0ID0gYygndmVydGljZXMnKSkKYmluZF9yb3dzKHBoZW5vX2NpcmN1aXRfcHJvdGVpbnMsIHNpZ19jaXJjdWl0X3Byb3RlaW5zKSAlPiUgZGlzdGluY3QoKSAtPiB1bmlvbl9kZl9ub2RlcwoKcGhlbm9fY2lyY3VpdF9lZGdlczwtIGFzX2RhdGFfZnJhbWUoeCA9IGNpcmN1aXRfcmVzX3BoZW5vLCB3aGF0ID0gYygnZWRnZXMnKSkKc2lnX2NpcmN1aXRfZWRnZXMgPC0gYXNfZGF0YV9mcmFtZSh4ID0gY2lyY3VpdF9yZXMsIHdoYXQgPSBjKCdlZGdlcycpKQpiaW5kX3Jvd3MocGhlbm9fY2lyY3VpdF9lZGdlcywgc2lnX2NpcmN1aXRfZWRnZXMpICU+JSBkaXN0aW5jdCgpIC0+IHVuaW9uX2RmX2VkZ2VzCgpncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IHVuaW9uX2RmX2VkZ2VzLCB2ZXJ0aWNlcyA9IHVuaW9uX2RmX25vZGVzKSAtPiBmaW5hbF9ncmFwaAoKd3JpdGVfcmRzKGZpbmFsX2dyYXBoLCAnLi4vcmVzdWx0cy9yZXNfc2Vucy9iY3JfaW5kZXBlbmRlbnRfbmV0d29yay5yZHMnKQoKUkN5Mzo6Y3JlYXRlTmV0d29ya0Zyb21JZ3JhcGgoaWdyYXBoPWZpbmFsX2dyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMCgnUkVTIHRvIHBoZW5vdHlwZXMgaz0nLCBrMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb24gPSAnUmVzIG5ldyBuZXcgYWxsIHBhdGhzIDInKQoKI2RhdGFfcGF0aCA8LSBzeXN0ZW0uZmlsZSgiZXh0ZGF0YSIsICJTUF9waGVub19sYXlvdXQueG1sIiwgcGFja2FnZSA9ICJTaWduYWxpbmdQcm9maWxlciIpCiNSQ3kzOjppbXBvcnRWaXN1YWxTdHlsZXMoZmlsZW5hbWUgPSBkYXRhX3BhdGgpClJDeTM6OnNldFZpc3VhbFN0eWxlKCdTUF9waGVub19sYXlvdXQnKQpgYGAKCiMjIyMgVmlzdWFsaXphdGlvbiBvZiBwcm8tc3Vydml2YWwgc2lnbmFsaW5nIGF4ZXMKVG8gZm9jdXMgb24gdGhlIHNpZ25hbGluZyBheGVzIGFjdGl2YXRpbmcgcHJvbGlmZXJhdGlvbiBhbmQgaW5oaWJpdGluZyBhcG9wdG9zaXMsIHdlIG9wdGltaXplZCB0aGUgQkNSLUFCTCBpbmRlcGVuZW5kZW50IG5ldHdvcmsgb24gYWN0aXZlIHByb2xpZmVyYXRpb24gYW5kIGluYWN0aXZlIGFwb3B0b3Npcy4KCmBgYHtyIGV2YWwgPSBGQUxTRX0KYmNyX2FibF9pbmRlcGVuZGVudCA8LSByZWFkUkRTKCcuLi9yZXN1bHRzL3Jlc19zZW5zL2Jjcl9pbmRlcGVuZGVudF9uZXR3b3JrLnJkcycpCm5vZGVzX2Jjcl9pbmRfbmV0d29yayA8LSBhc19kYXRhX2ZyYW1lKGJjcl9hYmxfaW5kZXBlbmRlbnQsIHdoYXQgPSAndmVydGljZXMnKQplZGdlc19iY3JfaW5kX25ldHdvcmsgPC0gYXNfZGF0YV9mcmFtZShiY3JfYWJsX2luZGVwZW5kZW50LCB3aGF0ID0gJ2VkZ2VzJykKCiMgSXNvbGF0ZSBwcm90ZWlucyBhbmQgcGhlbm90eXBlcwpwcm90ZWluc19kZiA8LSBub2Rlc19iY3JfaW5kX25ldHdvcmsgJT4lICNkcGx5cjo6ZmlsdGVyKG5hbWUgJWluJSBkcnVnZ2FiaWxpdHlfcmVzdWx0X3N1YiRnZW5lX25hbWUpICU+JQogIGRwbHlyOjpzZWxlY3QoZ2VuZV9uYW1lID0gbmFtZSwgVU5JUFJPVCwgZmluYWxfc2NvcmUgPSBjYXJuaXZhbF9hY3Rpdml0eSwgbWV0aG9kLCBtZikgJT4lCiAgZmlsdGVyKCFnZW5lX25hbWUgJWluJSBjKCdBUE9QVE9TSVMnLCAnUFJPTElGRVJBVElPTicpKQoKdGFyZ2V0X2RmIDwtIG5vZGVzX2Jjcl9pbmRfbmV0d29yayAlPiUgZHBseXI6OmZpbHRlcihuYW1lICVpbiUgYygnQVBPUFRPU0lTJywgJ1BST0xJRkVSQVRJT04nKSkKdGFyZ2V0X2RmJGNhcm5pdmFsX2FjdGl2aXR5IDwtIGMoLTEwMCwgMTAwKQp0YXJnZXRfZGYgPC0gdGFyZ2V0X2RmICU+JQogIGRwbHlyOjpzZWxlY3QoZ2VuZV9uYW1lID0gbmFtZSwgVU5JUFJPVCwgZmluYWxfc2NvcmUgPSBjYXJuaXZhbF9hY3Rpdml0eSwgbWV0aG9kLCBtZikKCiMgVHJhbnNmb3JtIHRoZSBvcHRpbWl6ZWQgbmV0d29yayBlZGdlcyBpbiBTSUYgZm9ybWF0CnBoZW5vX25haXZlX2RmIDwtIGVkZ2VzX2Jjcl9pbmRfbmV0d29yayAlPiUgZHBseXI6OnNlbGVjdChzb3VyY2UgPSBmcm9tLCBpbnRlcmFjdGlvbiA9IHNpZ24sIHRhcmdldCA9IHRvKQoKc29sdmVyID0gJ2NwbGV4JwpjYXJuaXZhbF9vcHRpb25zID0gZGVmYXVsdF9DQVJOSVZBTF9vcHRpb25zKHNvbHZlcikKb3V0cHV0MSA8LSBydW5fY2Fybml2YWxfYW5kX2NyZWF0ZV9ncmFwaChzb3VyY2VfZGYgPSBwcm90ZWluc19kZiAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0X2RmID0gdGFyZ2V0X2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5haXZlX25ldHdvcmsgPSB1bmlxdWUocGhlbm9fbmFpdmVfZGYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3RlaW5zX2RmID0gbm9kZXNfYmNyX2luZF9uZXR3b3JrICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChnZW5lX25hbWUgPSBuYW1lLCBVTklQUk9ULCBmaW5hbF9zY29yZSwgbWV0aG9kLCBtZiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAnaHVtYW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhcm5pdmFsX29wdGlvbnMgPSBjYXJuaXZhbF9vcHRpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3QgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGhfYXRsYXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoX3NpZiA9ICcuLi9yZXN1bHRzL3Jlc19zZW5zL2luZF9jaXJjdWl0X29wdGltaXplZC5zaWYnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfcmRzID0gJy4uL3Jlc3VsdHMvcmVzX3NlbnMvaW5kX2NpcmN1aXRfb3B0aW1pemVkLnJkcycpCgojIE1hcCBvbWljcyBvbiB0aGUgb3B0aW1pemVkIG1vZGVsCnBob3NwaG9fZGYgPC0gcmVhZF90c3YoJy4uL2lucHV0L3Bob3NwaG9fSzU2Ml9yZXNfc2Vuc19TUC50c3YnKQoKc3Bfb3V0cHV0X2RmIDwtIGV4cGFuZF9hbmRfbWFwX2VkZ2VzKG9wdGltaXplZF9vYmplY3QgPSBvdXRwdXQxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAnaHVtYW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGhvc3Bob19kZiA9IHBob3NwaG9fZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3QgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2l0aF9hdGxhcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoX3NpZiA9ICcuLi9yZXN1bHRzL3Jlc19zZW5zL2luZF9jaXJjdWl0X29wdGltaXplZF92YWxpZGF0ZWQuc2lmJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGhfcmRzID0gJy4uL3Jlc3VsdHMvcmVzX3NlbnMvaW5kX2NpcmN1aXRfb3B0aW1pemVkX29wdGltaXplZF92YWxpZGF0ZWQucmRzJykKCnNwX291dHB1dF9kZiRpZ3JhcGhfbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IHNwX291dHB1dF9kZiRlZGdlc19kZiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNlcyA9IHNwX291dHB1dF9kZiRub2Rlc19kZikKCmZpbmFsX3NwX3Zpc3VhbGl6YXRpb24gPC0gZm9ybWF0X2Zvcl92aXN1YWxpemF0aW9uKHNwX291dHB1dF9kZikKClJDeTM6OmNyZWF0ZU5ldHdvcmtGcm9tSWdyYXBoKGlncmFwaD1zcF9vdXRwdXRfZGYkaWdyYXBoX25ldHdvcmssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGFzdGUwKCdCQ1JfQUJMIGluZGVwZW5kZW50IG5ldHdvcmsgb3B0aW1pemVkJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb24gPSAnQkNSX0FCTCBpbmRlcGVuZGVudCcpCiNTZXQgaW4gQ3l0b3NjYXBlIHRoZSBTaWduYWxpbmdQcm9maWxlciBzdHlsZSBhdmFpbGFibGUgaW4gU2lnbmFsaW5nUHJvZmlsZXIgUiBwYWNrYWdlCiNkYXRhX3BhdGggPC0gc3lzdGVtLmZpbGUoImV4dGRhdGEiLCAiU1BfcGhlbm9fbGF5b3V0LnhtbCIsIHBhY2thZ2UgPSAiU2lnbmFsaW5nUHJvZmlsZXIiKQojUkN5Mzo6aW1wb3J0VmlzdWFsU3R5bGVzKGZpbGVuYW1lID0gZGF0YV9wYXRoKQpSQ3kzOjpzZXRWaXN1YWxTdHlsZSgnU1BfcGhlbm9fbGF5b3V0JykKYGBgCgpUaGVuLCB3ZSBjYW4gZXh0cmFjdGVkIHByby1zdXJ2aXZhbCBjaXJjdWl0cyB3aXRoIG1heGltdW0gcGF0aCBsZW5ndGggNC4KYGBge3IgZXZhbCA9IEZBTFNFfQoKc3Bfb2JqZWN0X25ldCA8LSByZWFkUkRTKCcuLi9yZXN1bHRzL3Jlc19zZW5zL2luZF9jaXJjdWl0X29wdGltaXplZF9vcHRpbWl6ZWRfdmFsaWRhdGVkLnJkcycpCm9wcG9zaXRlc19pbl9uZXR3b3Jrc19hbm5vIDwtIHJlYWRfdHN2KCAnLi4vcmVzdWx0cy9yZXNfc2Vucy9hY3RpdmF0ZWRfcHJvdGVpbnNfbmV0d29ya19uZXcudHN2JykKCiMgRm9ybWF0IGZvciB2aXN1YWxpemF0aW9uCnNwX29iamVjdF9uZXQkbm9kZXNfZGYgPC0gc3Bfb2JqZWN0X25ldCRub2Rlc19kZiAlPiUKICBtdXRhdGUoZ29sZF9zdGFuZGFyZCA9IGlmZWxzZShnZW5lX25hbWUgJWluJQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3Bwb3NpdGVzX2luX25ldHdvcmtzX2Fubm8kZ2VuZV9uYW1lLCAnWScsIE5BKSkKCnNwX29iamVjdF9uZXQkaWdyYXBoX25ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKGQgPSBzcF9vYmplY3RfbmV0JGVkZ2VzX2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2VzID0gc3Bfb2JqZWN0X25ldCRub2Rlc19kZikKCnNwX29iamVjdF9uZXQgPC0gZm9ybWF0X2Zvcl92aXN1YWxpemF0aW9uKHNwX29iamVjdF9uZXQpCgprID0gNApwaGVub190b19zdGFydF9jaXJjdWl0KFNQX29iamVjdCA9IHNwX29iamVjdF9uZXQsCiAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRfbm9kZXMgPSAgYyhvcHBvc2l0ZXNfaW5fbmV0d29ya3NfYW5ub19yZWNlcHRyJGdlbmVfbmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgcGhlbm90eXBlcyA9IGMoJ1BST0xJRkVSQVRJT04nLCAnQVBPUFRPU0lTJyksICNjKG9wcG9zaXRlcyRnZW5lX25hbWUpLAogICAgICAgICAgICAgICAgICAgICAgIGsgPSBrLAogICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0X3RvX3RvcCA9IFRSVUUpIC0+IGNpcmN1aXRfc3BlY2lmaWMKClJDeTM6OmNyZWF0ZU5ldHdvcmtGcm9tSWdyYXBoKGlncmFwaD1jaXJjdWl0X3NwZWNpZmljLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlMCgnYWxsIHJlYycsICcgayA9ICcsIGspLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsZWN0aW9uID0gJ0JDUl9BQkwgaW5kZXBlbmRlbnQnKQpSQ3kzOjpzZXRWaXN1YWxTdHlsZSgnU1BfcGhlbm9fbGF5b3V0JykKCmBgYAohWyoqQkNSLUFCTCBpbmRlcGVuZGVudCBzaWduYWxpbmcgYXhlcyBpbiBLNTYyLVIqKl0oLi9pbWcvQkNSX0FCTF9pbmRlcGVuZGVudC5wbmcpCgojIyBEcnVnZ2FiaWxpdHkgc2NvcmUgY29tcHV0YXRpb24KCkluIHRoZSAqKmRydWdnYWJpbGl0eSBzY29yZSoqIGNvbXB1dGF0aW9uLCB3ZSBjb25zaWRlciB0aGUgKip0b3BvbG9neSBzY29yZSogdGhhdCBpcyBjb21iaW5lZCB0byB0aGUgYWN0aXZhdGlvbiBzdGF0dXMgb2YgcHJvdGVpbnMuCgokJHRvcG9sb2d5c2NvcmUgPSBkZWdyZWVfe25vcm19K3BhdGhzX3thcG9wdG9zaXN9K3BhdGhzX3twcm9saWZlcmF0aW9ufSQkCgokJGRydWdnYWJpbGl0eXNjb3JlPXRvcG9sb2d5c2NvcmUgKiBhY3Rpdml0eS8xMDAkJAoKSGVyZSBpcyByZXBvcnRlZCB0aGUgY29kZS4gCmBgYHtyIGV2YWwgPSBGQUxTRX0KCiMgVmVjdG9yIG9mIGdlbmUgbmFtZXMgb2YgRkRBLWFwcHJvdmVkIGRydWcgdGFyZ2V0cyBmcm9tIGxpdGVyYXR1cmUgKFJFRikKZHJfbm9kZXMgPC0gYygiQkNMMiIgLCAiVE5GUlNGMTciICwgIkJDUl9BQkwiICwgIkZMVDQiICwgIktEUiIgLCAiRkxUMSIgLCAKICAgICAgICAgICAgICAiRkdGUiIgLCAiUERHRlJBICIgLCAiUERHRlJCIiAsICJSRVQiICwgIktJVCIgLCAiVElFMiIgLCAiRkxUMyIgLCAKICAgICAgICAgICAgICAiQlRLIiAsICJDQ1I0IiAsICJDRDE5IiAsICJNUzRBMSIgLCAiQ0QyMiIgLCAiVE5GUlNGOCIgLCAiQ0QzOCIgLCAKICAgICAgICAgICAgICAiQ0Q3OUIiICwgIkNEQSIgLCAiUERHRlJBIiAsICJQUktDQSIgLCAiQU1QSyIgLCAiQ0RLMSIgLCAiU1lLIiAsICJDUkJOIiAsIAogICAgICAgICAgICAgICJETkFfREFNQUdFIiAsICJSTk1UIiAsICJFWkgyIiAsICJBWEwiICwgIkFMSyIgLCAiSURIMSIgLCAiSURIMiIgLAogICAgICAgICAgICAgICJKQUsxIiAsICJKQUsyIiAsICJQRENEMSIgLCAiUHJvdGVhc29tZSIgLCAiUHJvdGVpbiBsZXZlbCIgLCAKICAgICAgICAgICAgICAiU0xBTUY3IiAsICJTTU8gcmVjZXB0b3IiICwgIlNSQyIgLCAiQUJMMSIgLCAiVE9QMkEiICwgIlR1YnVsaW4iICwgIlhQTzEiICwgCiAgICAgICAgICAgICAgIkROTVQzQSIgLCAiUEkzSyIgLCAiUElLM0MyQSIgLCAiUElLM0MyQiIgLCAiUElLM0MzIiAsICJQSUszQ0EiICwgIlBJSzNDQiIgLCAKICAgICAgICAgICAgICAiUElLM0NEIiAsICJQSUszQ0ciICwgIlBJSzNSMSIgLCAiUElLM1IyIiAsICJQSUszUjMiICwgIkROTVQzQiIgLCAiRE5NVDEiICwgIlBBUlAxIikKCgpkcnVnZ2FiaWxpdHlfbmV0d29yayA8LSByZWFkUkRTKCcuLi9yZXN1bHRzL3Jlc19zZW5zL2Jjcl9pbmRlcGVuZGVudF9uZXR3b3JrLnJkcycpCmRydWdnX25ldF9jbGVhbiA8LSByZW1vdmVfbm9kZXNfYW5kX2ludGVyYWN0b3JzKGdyYXBoID0gZHJ1Z2dhYmlsaXR5X25ldHdvcmspCgojIENvbXB1dGUgdGhlIG51bWJlciBvZiBpbmhpYml0b3J5IHBhdGhzIHRvIGFwb3B0b3NpcwpuX3BhdGhzX2FwbyA8LSBjKCkKCmlfdiA9IDEKZm9yKGlfdiBpbiBjKDE6bGVuZ3RoKFYoZHJ1Z2dfbmV0X2NsZWFuKSRuYW1lKSkpewoKICB2ZXJ0ZXggPC0gVihkcnVnZ19uZXRfY2xlYW4pJG5hbWVbaV92XQoKICBhbGxfcGF0aHNfYWxsIDwtIGlncmFwaDo6YWxsX3NpbXBsZV9wYXRocyhncmFwaCA9IGRydWdnX25ldF9jbGVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb20gPSBWKGRydWdnX25ldF9jbGVhbilbVihkcnVnZ19uZXRfY2xlYW4pJG5hbWUgPT0gdmVydGV4XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gVihkcnVnZ19uZXRfY2xlYW4pJG5hbWVbVihkcnVnZ19uZXRfY2xlYW4pJG5hbWUgPT0gJ0FQT1BUT1NJUyddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZSA9ICdvdXQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3V0b2ZmID0gMTApCgogIGlmKGxlbmd0aChhbGxfcGF0aHNfYWxsKSAhPSAwKXsKICAgIGFsbF9wYXRocyA8LSBmaWx0ZXJfcGF0aHNfcmF3KGdyYXBoID0gZHJ1Z2dfbmV0X2NsZWFuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsX3BhdGhzID0gYWxsX3BhdGhzX2FsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhdXNhbGl0eSA9ICctMScsbW9kZSA9ICdvdXQnKQoKICAgICMgSWYgdGhlcmUgYXJlIGZpbHRlcmVkIHBhdGhzIGFuZCBhcmUgbG9uZ2VyIHBhdGhzIHRoYW4gb25lLCBrZWVwIHRoZW0gYmVjYXVzZSB0aGUgb3RoZXIgaXMgYW4gaW5kaXJlY3QgaW50ZXJhY3Rpb24hCiAgICBpZihsZW5ndGgoYWxsX3BhdGhzKSAhPSAwKXsKICAgICAgd2VpZ2h0ZWRfc3VtIDwtIHJlcCgxLCBsZW5ndGgoYWxsX3BhdGhzKSkgLyB1bmxpc3QobGFwcGx5KGFsbF9wYXRocywgZnVuY3Rpb24oeCl7bGVuZ3RoKHgpfSkpCiAgICAgIGxlbmd0aF9pIDwtIG1lYW4od2VpZ2h0ZWRfc3VtKQogICAgfWVsc2V7CiAgICAgIGxlbmd0aF9pID0gMAogICAgfQogIH1lbHNlewogICAgbGVuZ3RoX2kgPSAwCiAgfQoKICBuX3BhdGhzX2FwbyA8LSBjKG5fcGF0aHNfYXBvLCBsZW5ndGhfaSkKCn0KCm5hbWVzKG5fcGF0aHNfYXBvKSA8LSBWKGRydWdnX25ldF9jbGVhbikkbmFtZQoKIyBDb21wdXRlIHRoZSBudW1iZXIgb2YgYWN0aXZhdG9yeSBwYXRocyB0byBwcm9saWZlcmF0aW9uCgpuX3BhdGhzX3BybyA8LSBjKCkKCmZvcihpX3YgaW4gYygxOmxlbmd0aChWKGRydWdnX25ldF9jbGVhbikkbmFtZSkpKXsKCiAgdmVydGV4IDwtIFYoZHJ1Z2dfbmV0X2NsZWFuKSRuYW1lW2lfdl0KCiAgYWxsX3BhdGhzX2FsbCA8LSBpZ3JhcGg6OmFsbF9zaW1wbGVfcGF0aHMoZ3JhcGggPSBkcnVnZ19uZXRfY2xlYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSA9IFYoZHJ1Z2dfbmV0X2NsZWFuKVtWKGRydWdnX25ldF9jbGVhbikkbmFtZSA9PSB2ZXJ0ZXhdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gVihkcnVnZ19uZXRfY2xlYW4pJG5hbWVbVihkcnVnZ19uZXRfY2xlYW4pJG5hbWUgPT0gJ1BST0xJRkVSQVRJT04nXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlID0gJ291dCcsIGN1dG9mZiA9IDEwKQoKCiAgaWYobGVuZ3RoKGFsbF9wYXRoc19hbGwpICE9IDApewoKICAgIGFsbF9wYXRocyA8LSBmaWx0ZXJfcGF0aHNfcmF3KGdyYXBoID0gZHJ1Z2dfbmV0X2NsZWFuLCBhbGxfcGF0aHMgPSBhbGxfcGF0aHNfYWxsLCBjYXVzYWxpdHkgPSAnMScsbW9kZSA9ICdvdXQnKQoKICAgIGlmKGxlbmd0aChhbGxfcGF0aHMpICE9IDApewogICAgICB3ZWlnaHRlZF9zdW0gPC0gcmVwKDEsIGxlbmd0aChhbGxfcGF0aHMpKSAvIHVubGlzdChsYXBwbHkoYWxsX3BhdGhzLCBmdW5jdGlvbih4KXtsZW5ndGgoeCl9KSkKICAgICAgbGVuZ3RoX2kgPC0gbWVhbih3ZWlnaHRlZF9zdW0pCiAgICB9ZWxzZXsKICAgICAgbGVuZ3RoX2kgPSAwCiAgICB9CgogIH1lbHNlewogICAgbGVuZ3RoX2kgPSAwCiAgfQoKICBuX3BhdGhzX3BybyA8LSBjKG5fcGF0aHNfcHJvLCBsZW5ndGhfaSkKCn0KCiMgQ3JlYXRlIGEgdGliYmxlIHdpdGggdGhlIG51bWJlciBvZiBwYXRocyBmb3IgcHJvbGlmZXJhdGlvbiBhbmQgYXBvcHRvc2lzCgpuYW1lcyhuX3BhdGhzX2FwbykgPC0gVihkcnVnZ19uZXRfY2xlYW4pJG5hbWUKbmFtZXMobl9wYXRoc19wcm8pIDwtIFYoZHJ1Z2dfbmV0X2NsZWFuKSRuYW1lCgp0aWJibGUoZ2VuZV9uYW1lID0gbmFtZXMobl9wYXRoc19wcm8pLAogICAgICAgbl9wYXRoc19wcm8gPSBuX3BhdGhzX3BybywKICAgICAgIG5fcGF0aHNfYXBvID0gbl9wYXRoc19hcG8pIC0+IHBhdGhzX2RmCgpzY29yZV9kZiA8LSB0aWJibGUoZ2VuZV9uYW1lID0gbmFtZXMoZGVncmVlKGRydWdnX25ldF9jbGVhbiwgbW9kZSA9ICdpbicpKSwKICAgICAgICAgICAgICAgICAgIGRlZ3JlZSA9IGRlZ3JlZShkcnVnZ19uZXRfY2xlYW4sIG1vZGUgPSAnYWxsJyksCiAgICAgICAgICAgICAgICAgICBpbmRlZ3JlZSA9ICBkZWdyZWUoZHJ1Z2dfbmV0X2NsZWFuLCBtb2RlID0gJ2luJyksCiAgICAgICAgICAgICAgICAgICBvdXRfZGVncmVlID0gIGRlZ3JlZShkcnVnZ19uZXRfY2xlYW4sIG1vZGUgPSAnb3V0JyksCiAgICAgICAgICAgICAgICAgICBuX3BhdGhzX2FwbyA9IHBhdGhzX2RmJG5fcGF0aHNfYXBvLAogICAgICAgICAgICAgICAgICAgbl9wYXRoc19wcm8gPSBwYXRoc19kZiRuX3BhdGhzX3BybywKICAgICAgICAgICAgICAgICAgIGFjdGl2aXR5ID0gVihkcnVnZ19uZXRfY2xlYW4pJGNhcm5pdmFsX2FjdGl2aXR5LAogICAgICAgICAgICAgICAgICAgdGVzdGVkID0gVihkcnVnZ19uZXRfY2xlYW4pJFNlbnNfZmluYWwpCgpzY29yZV9kZiAlPiUgbXV0YXRlKAogIG5vcm1fZGVncmVlID0gbG9nKGRlZ3JlZSsxKS9tYXgoc2NvcmVfZGYkZGVncmVlKSwKICBub3JtX2luZGVncmVlID0gbG9nKGluZGVncmVlKzEpL21heChsb2coc2NvcmVfZGYkaW5kZWdyZWUgKyAxKSksCiAgbm9ybV9vdXRkZWdyZWUgPSBsb2cob3V0X2RlZ3JlZSsxKS9tYXgobG9nKHNjb3JlX2RmJG91dF9kZWdyZWUgKyAxKSksCiAgbm9ybV9uX3BhdGhzX2FwbyA9IGxvZyhuX3BhdGhzX2FwbysxKS9tYXgobG9nKHNjb3JlX2RmJG5fcGF0aHNfYXBvICsgMSkpLAogIG5vcm1fbl9wYXRoc19wcm8gPSBsb2cobl9wYXRoc19wcm8rMSkvbWF4KGxvZyhzY29yZV9kZiRuX3BhdGhzX3BybyArIDEpKSwKICBkcnVnZ2FibGUgPSBpZmVsc2UoZ2VuZV9uYW1lICVpbiUgZHJfbm9kZXMsIFRSVUUsIEZBTFNFKQopIC0+IHNjb3JlX2RmCgpzY29yZV9kZiA8LSBzY29yZV9kZiAlPiUKICBtdXRhdGUodG9wb2xvZ3lfc2NvcmUgPSAobm9ybV9pbmRlZ3JlZSArIG5vcm1fb3V0ZGVncmVlICsgbm9ybV9uX3BhdGhzX2FwbyArIG5vcm1fbl9wYXRoc19wcm8pLzQpCgpzY29yZV9kZiAlPiUKICBtdXRhdGUoZHJ1Z19zY29yZSA9IHRvcG9sb2d5X3Njb3JlICogYWN0aXZpdHkvMTAwKSAtPiBzY29yZV9kZgoKc2NvcmVfZGYgJT4lIHJlbG9jYXRlKGdlbmVfbmFtZSwgZHJ1Z19zY29yZSwgZHJ1Z2dhYmxlLCB0b3BvbG9neV9zY29yZSkgJT4lCiAgYXJyYW5nZShkZXNjKGRydWdfc2NvcmUpKSAtPiBzY29yZV9kZgoKd3JpdGVfdHN2KHNjb3JlX2RmLCAnLi4vcmVzdWx0cy9yZXNfc2Vucy9kcnVnZ2FiaWxpdHlfc2NvcmUvZHJ1Z2dhYmlsaXR5X3Njb3JlLnRzdicpCmBgYAoKPiBSZXN1bHRpbmcgdGFibGUKCmBgYHtyfQpzY29yZV9kZiA8LSByZWFkcjo6cmVhZF90c3YoJy4uL3Jlc3VsdHMvcmVzX3NlbnMvZHJ1Z2dhYmlsaXR5X3Njb3JlL2RydWdnYWJpbGl0eV9zY29yZS50c3YnLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpEVDo6ZGF0YXRhYmxlKHNjb3JlX2RmKQpgYGAKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgo+IFBsb3QKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9NH0Kc2NvcmVfZGYgJT4lCiAgbXV0YXRlKGRydWdfc2NvcmVfbm9ybSA9IGRydWdfc2NvcmUgLyBtYXgoZHJ1Z19zY29yZSkpIC0+IHNjb3JlX2RmCgpzY29yZV9kZiRnZW5lX25hbWUxID0gZmN0X3Jlb3JkZXIoc2NvcmVfZGYkZ2VuZV9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NvcmVfZGYkZHJ1Z19zY29yZSkKCnNjb3JlX2RmICU+JSBmaWx0ZXIoZHJ1Z2dhYmxlID09IFRSVUUpIC0+IHRvcF9yZXN1CnNjb3JlX2RmICU+JSBmaWx0ZXIoZHJ1Z2dhYmxlID09IEZBTFNFKSAtPiBib3R0b21fcmVzdQoKYmluZF9yb3dzKGJvdHRvbV9yZXN1LCB0b3BfcmVzdSkgLT4gc2NvcmVfZGZfb3JkZXJlZApzY29yZV9kZl9vcmRlcmVkIDwtIHNjb3JlX2RmX29yZGVyZWQgJT4lCiAgbXV0YXRlKGxhYmVsX25hbWUgPSBpZmVsc2UoZHJ1Z2dhYmxlID09IFRSVUUsIGFzLmNoYXJhY3RlcihnZW5lX25hbWUpLCAnJykpCgpnZ3Bsb3Qoc2NvcmVfZGZfb3JkZXJlZCwgYWVzKHggPSBnZW5lX25hbWUxLCB5ID0gZHJ1Z19zY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZHJ1Z2dhYmxlLCBsYWJlbCA9IGxhYmVsX25hbWUpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMS41LCBhbHBoYSA9IDAuOCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICB5bGFiKCdEcnVnZ2FiaWxpdHkgc2NvcmUgaW4gUmVzaXN0YW50IHZzIEN0cmwnKSArCiAgeGxhYignR2VuZSBOYW1lJykgKwogIHRoZW1lX2NsYXNzaWMoKSsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygnZ3JleScsICdyZWQzJykpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLCAKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsKICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwobWF4Lm92ZXJsYXBzID0gMTAwKSAKYGBgCioqRmlndXJlIDZCKiogU2NhdHRlcnBsb3Qgb2YgRHJ1Z2dhYmlsaXR5IFNjb3JlIHJlc3VsdHMgd2hlcmUgZHJ1ZyB0YXJnZXRzICh4LWF4aXMpIGFyZSByYW5rZWQgYWNjb3JkaW5nIHRvIHRoZSBEcnVnZ2FiaWxpdHkgU2NvcmUgKHktYXhpcykuIFRhcmdldHMgb2YgRkRBLWFwcHJvdmVkIGRydWdzIGFyZSByZXBvcnRlZCBpbiByZWQuCgoKIyMjIyMgRXhwZXJpbWVudGFsIHZhbGlkYXRpb24gb2YgZHJ1Z2dhYmlsaXR5IHNjb3JlCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD00fQpvYnNfaWM1MCA8LSByZWFkX3RzdignLi4vcmVzdWx0cy9yZXNfc2Vucy9kcnVnZ2FiaWxpdHlfc2NvcmUvZGF0YV92YWxpZGF0aW9uX2RydWdnYWJpbGl0eS50c3YnLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpvYnNfaWM1MCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCdnZW5lX25hbWUnKSAtPiBvYnNfaWM1MF9tYXRyaXgKb2JzX2ljNTBfbWF0cml4X2xvZyA8LSAtbG9nMihvYnNfaWM1MF9tYXRyaXgpCm9ic19pYzUwX21hdHJpeF9sb2dbaXMubmEob2JzX2ljNTBfbWF0cml4X2xvZyldIDwtIDAKZHJ1Z2dfc2NvcmUgPC0gb2JzX2ljNTBfbWF0cml4X2xvZyAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCdnZW5lX25hbWUnKSAlPiUKICBtdXRhdGUob2JzZXJ2ZWQgPSBJQzUwX1JlcyAtIElDNTBfU2VucykKCiMgQ29tYmluZSB0aGUgdHdvIGVsZW1lbnRzCmlubmVyX2pvaW4oc2NvcmVfZGYgJT4lCiAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGdlbmVfbmFtZSwgZHJ1Z19zY29yZSwgZHJ1Z19zY29yZV9ub3JtKSwKICAgICAgICAgICBkcnVnZ19zY29yZSwgYnkgPSAnZ2VuZV9uYW1lJykgLT4gcmVzdWx0aW5nX2RmCgojIFRyYW5zZm9ybSBpbiBsb25nIGZvcm1hdApsb25nX2RmIDwtIHJlc3VsdGluZ19kZiAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoJ0lDNTBfU2VucycsICdJQzUwX1JlcycpKQoKIyBQTE9UMjogdmFsaWRhdGlvbiBvZiBkcnVnZ2FiaWxpdHkgc2NvcmUKZ2dwbG90KGxvbmdfZGYsCiAgICAgICBhZXMoeCA9IGRydWdfc2NvcmUsIHkgPSB2YWx1ZSwgY29sb3IgPSBuYW1lLCBsYWJlbCA9IGdlbmVfbmFtZSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAxLjUsIGFscGhhID0gMSkgKwogIHhsYWIoJ0RydWdnYWJpbGl0eSBzY29yZScpICsKICB5bGFiKCctbG9nMihJQzUwKScpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChtYXgub3ZlcmxhcHMgPSAxMDApICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCcjQ0QxQzY3JywgJyM5N0JERTQnKSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJywgCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKCmBgYAoKKipGaWd1cmUgNUQqKiBEcnVnZ2FiaWxpdHkgU2NvcmUgdmFsaWRhdGlvbiBhY2NvcmRpbmcgdG8gSUM1MCBkZXJpdmVkIGZyb20gTVRUIHZpYWJpbGl0eSBhc3NheXMgaW4gSzU2MiAoYmx1ZSkgYW5kIEs1NjItUiBjZWxscyAocmVkKS4KCiMgQ29uY2x1c2lvbiB7LnVubnVtYmVyZWR9CkFnZ2l1bmdlcmUgcXVpIGxhIGNvbmNsdXNpb25lIGRlbCBwYXBlciAKCiMgUiBzZXNzaW9uIGluZm8gey51bm51bWJlcmVkfQoKYGBge3Igc2Vzc2lvbiBpbmZvLCBjb21tZW50PSIifQp4ZnVuOjpzZXNzaW9uX2luZm8oKQpgYGAKCiMgUmVmZXJlbmNlcyB7LnVubnVtYmVyZWR9Cg==